From 748a761b83c1adf89ad16c5069f829fa0a90e31b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 1 Mar 2012 08:26:33 +0000 Subject: LRN: updates to pseudonym API from #1952, adding namespace manager --- contrib/Makefile.am | 1 + contrib/gnunet_fs_gtk_main_window.glade | 9 + contrib/gnunet_fs_gtk_namespace_manager.glade | 628 +++++++++++++ src/fs/Makefile.am | 3 +- src/fs/gnunet-fs-gtk_common.c | 112 +++ src/fs/gnunet-fs-gtk_common.h | 43 + src/fs/gnunet-fs-gtk_event-handler.c | 8 + .../gnunet-fs-gtk_main-window-namespace-dropdown.c | 24 +- src/fs/gnunet-fs-gtk_namespace_manager.c | 970 +++++++++++++++++++++ 9 files changed, 1788 insertions(+), 10 deletions(-) create mode 100644 contrib/gnunet_fs_gtk_namespace_manager.glade create mode 100644 src/fs/gnunet-fs-gtk_namespace_manager.c diff --git a/contrib/Makefile.am b/contrib/Makefile.am index 2ac5e305..b796dde4 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -17,6 +17,7 @@ pkgdata_DATA = \ gnunet_fs_gtk_create_namespace_dialog.glade \ gnunet_fs_gtk_download_as_dialog.glade \ gnunet_fs_gtk_main_window.glade \ + gnunet_fs_gtk_namespace_manager.glade \ gnunet_fs_gtk_edit_publication.glade \ gnunet_fs_gtk_open_directory_dialog.glade \ gnunet_fs_gtk_open_url_dialog.glade \ diff --git a/contrib/gnunet_fs_gtk_main_window.glade b/contrib/gnunet_fs_gtk_main_window.glade index bf520f0d..710c7697 100644 --- a/contrib/gnunet_fs_gtk_main_window.glade +++ b/contrib/gnunet_fs_gtk_main_window.glade @@ -249,6 +249,15 @@ + + + True + Opens namespace manager dialog to adjust the list of namespaces you want to use, as well as get detailed information about all discovered namespaces. + _Manage namespaces + True + + + True diff --git a/contrib/gnunet_fs_gtk_namespace_manager.glade b/contrib/gnunet_fs_gtk_namespace_manager.glade new file mode 100644 index 00000000..211d4738 --- /dev/null +++ b/contrib/gnunet_fs_gtk_namespace_manager.glade @@ -0,0 +1,628 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + False + 5 + True + dialog + True + + + + True + False + 2 + + + True + False + end + + + gtk-apply + False + True + True + True + Saves all changes made in this dialog to disk without closing the dialog. + True + + + False + False + 0 + + + + + gtk-ok + False + True + True + True + Saves all changes made in this dialog to disk and closes the dialog. + True + + + False + False + 1 + + + + + gtk-cancel + False + True + True + True + Closes the dialog. Changes made in this dialog will not be preserved. + True + + + False + False + 2 + + + + + False + True + end + 0 + + + + + True + True + + + True + True + + + True + False + + + True + False + Known namespaces: +Select a namespace to see its complete metadata. Click "Delete" to delete (forget) namespace. +Namespace names are editable. + + + False + False + 0 + + + + + True + True + GNUNET_GTK_namespace_manager_known_namespaces_hadj + GNUNET_GTK_namespace_manager_known_namespaces_vadj + automatic + automatic + in + + + True + True + GNUNET_GTK_namespace_manager_known_liststore + GNUNET_GTK_namespace_manager_known_namespaces_hadj + GNUNET_GTK_namespace_manager_known_namespaces_vadj + True + 2 + False + + + Is mine + True + True + 0 + + + False + + + 0 + + + + + + + Rank + True + True + 1 + + + + 1 + + + + + + + Name + True + True + 2 + + + True + + + + + 2 + + + + + + + Identifier + True + True + 3 + + + + 3 + + + + + + + + + True + True + 1 + + + + + True + False + cursor + 5 + 5 + end + + + gtk-delete + False + True + True + True + Makes GNUnet "forget" about selected known namespace. +However, GNUnet will be able to learn about this namespace, if it ever discovers it again. + True + + + + False + False + 0 + + + + + Swap _Rank + False + True + True + True + Changes the rank value of the selected namespace in "Known namespaces" list. +If it had rank 0, it's given rank -1, otherwise the sign of its rank is flipped. +Only namespaces with positive ranks are displayed in "Namespace order" list. + True + + + + False + False + 1 + + + + + False + False + 2 + + + + + True + False + + + + + True + False + + + True + False + Namespace order: +Drag rows to change namespace order, click "Apply" to save it. + + + False + False + 0 + + + + + True + True + GNUNET_GTK_namespace_manager_namespace_order_hadj + GNUNET_GTK_namespace_manager_namespace_order_vadj + automatic + automatic + in + + + True + True + GNUNET_GTK_namespace_manager_namespace_order_liststore + GNUNET_GTK_namespace_manager_namespace_order_hadj + GNUNET_GTK_namespace_manager_namespace_order_vadj + False + True + True + 0 + False + True + + + Rank + True + + + + + 0 + + + + + + + Name + True + + + + + 1 + + + + + + + Identifier + True + + + + + 2 + + + + + + + + + True + True + 1 + + + + + True + False + 5 + end + + + gtk-apply + False + True + True + True + Convert the order in which namespaces are arranged in "Namespace order" list to ranks. +Top namespace is assigned rank 0, namespace below it - rank 1, and so on. + True + + + + False + False + 0 + + + + + False + False + 2 + + + + + True + False + + + + + True + False + + + + + True + False + + + True + False + Selected namespace details: +Metadata can be <s>added,</s> deleted and edited. Click "Apply" to save metadata changes. + True + + + False + False + 0 + + + + + True + True + GNUNET_GTK_namespace_manager_namespace_details_hadj + GNUNET_GTK_namespace_manager_namespace_details_vadj + automatic + automatic + in + + + True + True + GNUNET_GTK_namespace_manager_namespace_details_liststore + GNUNET_GTK_namespace_manager_namespace_details_hadj + GNUNET_GTK_namespace_manager_namespace_details_vadj + False + True + 0 + False + True + both + + + Type + + + + + + 2 + + + + + + + Value + + + True + + + + 5 + + + + + + + + + True + True + 1 + + + + + True + False + 5 + 5 + end + + + gtk-add + False + True + False + True + True + Adds a new metadata Type=Value pair to the list. +This functionality is not available at the moment. + True + + + + False + False + 0 + + + + + gtk-delete + False + True + True + True + Removes selected Type=Value pair from metadata list. +The change will not last unless you click on "Apply" button before closing the window or selecing some other known namespace. + True + + + + False + False + 1 + + + + + gtk-apply + False + True + False + True + True + Applies changes made in metadata list to currently selected known namespace. + True + + + + False + False + 2 + + + + + False + False + 2 + + + + + True + False + + + + + True + True + 1 + + + + + + GNUNET_GTK_namespace_manager_apply_button + GNUNET_GTK_namespace_manager_ok_button + GNUNET_GTK_namespace_manager_cancel_button + + + + + + + + + + + + + + + + + + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + + + + + + + + + + + + + + + 100 + 1 + 10 + + diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index 07935135..20d8a7da 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -25,7 +25,8 @@ gnunet_fs_gtk_SOURCES = \ gnunet-fs-gtk_open-directory.c \ gnunet-fs-gtk_open-uri.c \ gnunet-fs-gtk_publish-dialog.c \ - gnunet-fs-gtk_publish-edit-dialog.c gnunet-fs-gtk_publish-edit-dialog.h + gnunet-fs-gtk_publish-edit-dialog.c gnunet-fs-gtk_publish-edit-dialog.h \ + gnunet-fs-gtk_namespace_manager.c gnunet-fs-gtk_namespace_manager.h gnunet_fs_gtk_LDADD = \ $(top_builddir)/src/lib/libgnunetgtk.la \ @GTK_LIBS@ \ diff --git a/src/fs/gnunet-fs-gtk_common.c b/src/fs/gnunet-fs-gtk_common.c index 8ca006e3..82d93e8f 100644 --- a/src/fs/gnunet-fs-gtk_common.c +++ b/src/fs/gnunet-fs-gtk_common.c @@ -416,5 +416,117 @@ GNUNET_FS_GTK_handle_uri (const struct GNUNET_FS_Uri *uri) GNUNET_break (0); } +/* Largest rating value among all namespaces. INT_MIN means "undefined" */ +static int largest_namespace_rating = INT_MIN; + + +/** + * Helper function for finding the largest namespace rating. + * + * @param cls closure + * @param pseudonym pseudonym hash + * @param md metadata container + * @param rating rating + * @return GNUNET_OK to keep iterating + */ +static int +find_largest_namespace_rating_iterator (void *cls, + const GNUNET_HashCode *pseudonym, const char *name, + const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + int *largest = cls; + if (*largest < rating) + *largest = rating; + return GNUNET_OK; +} + +/** + * Finds largest namespace rating. + * Used to calculate a rating for newly discovered namespaces. + * Returns from cache, if possible. + * + * @return largest namespace rating. Might be negative and even. INT_MIN means + * that no namespaces are known. + */ +int +GNUNET_GTK_find_largest_namespace_rating () +{ + if (largest_namespace_rating != INT_MIN) + return largest_namespace_rating; + (void) GNUNET_PSEUDONYM_list_all (GNUNET_FS_GTK_get_configuration (), + find_largest_namespace_rating_iterator, &largest_namespace_rating); + return largest_namespace_rating; +} + +/** + * Sets largest namespace rating. + * Used to change cached largest namespace rating, when namespace list + * was changed in a way that is easy to track. + * If namespace list was changed in a way that makes it difficult to + * decide upon the new value, set new value to INT_MIN. + * + * @param new_value new value for the rating. + */ +void +GNUNET_GTK_set_largest_namespace_rating (int new_value) +{ + largest_namespace_rating = new_value; +} + +/** + * Converts a GtkTreeRowReference to a GtkTreeIter. + * + * @param rr row reference + * @param iter pointer to an iter structure to fill + * @return GNUNET_OK if iter was filled, GNUNET_SYSERR otherwise + */ +int +GNUNET_GTK_get_iter_from_reference (GtkTreeRowReference *rr, GtkTreeIter *iter) +{ + int result = GNUNET_SYSERR; + if (rr != NULL) + { + if (gtk_tree_row_reference_valid (rr)) + { + GtkTreePath *path; + GtkTreeModel *model; + path = gtk_tree_row_reference_get_path (rr); + model = gtk_tree_row_reference_get_model (rr); + if (path != NULL && model != NULL) + { + if (gtk_tree_model_get_iter (model, + iter, path)) + result = GNUNET_OK; + gtk_tree_path_free (path); + } + } + } + return result; +} + +/** + * Creates a GtkTreeRowReference from a GtkTreeIter. + * + * @param model a model to reference + * @param iter an iter that points to a row in the model + * @return newly created reference or NULL in case of error + */ +GtkTreeRowReference * +GNUNET_GTK_get_reference_from_iter (GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkTreeRowReference *result = NULL; + if (iter != NULL && model != NULL) + { + GtkTreePath *path = gtk_tree_model_get_path (model, iter); + if (path != NULL) + { + result = gtk_tree_row_reference_new (model, path); + gtk_tree_path_free (path); + } + } + return result; +} + /* end of gnunet-fs-gtk-common.c */ diff --git a/src/fs/gnunet-fs-gtk_common.h b/src/fs/gnunet-fs-gtk_common.h index b5048d7c..30766956 100644 --- a/src/fs/gnunet-fs-gtk_common.h +++ b/src/fs/gnunet-fs-gtk_common.h @@ -147,5 +147,48 @@ GNUNET_FS_GTK_get_description_from_metadata ( void GNUNET_FS_GTK_handle_uri (const struct GNUNET_FS_Uri *uri); +/** + * Finds largest namespace rating. + * Used to calculate a rating for newly discovered namespaces. + * Returns from cache, if possible. + * + * @return largest namespace rating. Might be negative and even. INT_MIN means + * that no namespaces are known. + */ +int +GNUNET_GTK_find_largest_namespace_rating (); + +/** + * Sets largest namespace rating. + * Used to change cached largest namespace rating, when namespace list + * was changed in a way that is easy to track. + * If namespace list was changed in a way that makes it difficult to + * decide upon the new value, set new value to INT_MIN. + * + * @param new_value new value for the rating. + */ +void +GNUNET_GTK_set_largest_namespace_rating (int new_value); + +/** + * Converts a GtkTreeRowReference to a GtkTreeIter. + * + * @param rr row reference + * @param iter pointer to an iter structure to fill + * @return GNUNET_OK if iter was filled, GNUNET_SYSERR otherwise + */ +int +GNUNET_GTK_get_iter_from_reference (GtkTreeRowReference *rr, GtkTreeIter *iter); + +/** + * Creates a GtkTreeRowReference from a GtkTreeIter. + * + * @param model a model to reference + * @param iter an iter that points to a row in the model + * @return newly created reference or NULL in case of error + */ +GtkTreeRowReference * +GNUNET_GTK_get_reference_from_iter (GtkTreeModel *model, GtkTreeIter *iter); + #endif /* end of gnunet-fs-gtk-common.h */ diff --git a/src/fs/gnunet-fs-gtk_event-handler.c b/src/fs/gnunet-fs-gtk_event-handler.c index 4017e10f..0c7606c8 100644 --- a/src/fs/gnunet-fs-gtk_event-handler.c +++ b/src/fs/gnunet-fs-gtk_event-handler.c @@ -27,6 +27,7 @@ #include "gnunet-fs-gtk_common.h" #include "gnunet-fs-gtk_download-save-as.h" #include "gnunet-fs-gtk_event-handler.h" +#include "gnunet-fs-gtk_namespace_manager.h" /** @@ -3030,5 +3031,12 @@ GNUNET_GTK_fs_event_handler (void *cls, return NULL; } +void +GNUNET_GTK_main_menu_file_manage_pseudonyms_activate_cb (GtkMenuItem *menuitem, + gpointer user_data) +{ + GNUNET_GTK_namespace_manager_open (); +} + /* end of gnunet-fs-gtk-event_handler.c */ diff --git a/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c b/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c index cb5dc461..818caa6c 100644 --- a/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c +++ b/src/fs/gnunet-fs-gtk_main-window-namespace-dropdown.c @@ -322,11 +322,12 @@ GNUNET_FS_GTK_search_namespace_dropdown_button_toggled_cb (GtkToggleButton * */ static int add_namespace_to_ts (void *cls, const GNUNET_HashCode * pseudonym, + const char *name, const char *unique_name, const struct GNUNET_CONTAINER_MetaData *md, int rating) { GtkTreeStore *ts = cls; char *root; - char *ns_name; + char *ns_name, *unique_ns_name; GNUNET_HashCode *nsid; char *description; int desc_is_a_dup; @@ -335,9 +336,14 @@ add_namespace_to_ts (void *cls, const GNUNET_HashCode * pseudonym, struct GNUNET_FS_Uri *uri; GtkTreeIter iter; - ns_name = - GNUNET_PSEUDONYM_id_to_name (GNUNET_FS_GTK_get_configuration (), - pseudonym); + if (rating < 0) + return GNUNET_OK; + + GNUNET_PSEUDONYM_get_info (GNUNET_FS_GTK_get_configuration (), + pseudonym, NULL, NULL, &ns_name, NULL); + unique_ns_name = GNUNET_PSEUDONYM_name_uniquify ( + GNUNET_FS_GTK_get_configuration (), pseudonym, ns_name, NULL); + GNUNET_free (ns_name); nsid = GNUNET_malloc (sizeof (GNUNET_HashCode)); *nsid = *pseudonym; root = NULL; @@ -352,13 +358,13 @@ add_namespace_to_ts (void *cls, const GNUNET_HashCode * pseudonym, GNUNET_FS_uri_destroy (uri); } description = GNUNET_FS_GTK_get_description_from_metadata (md, &desc_is_a_dup); - gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, - 0, ns_name, - 1, nsid, + gtk_tree_store_insert_with_values (ts, &iter, NULL, G_MAXINT, + 0, unique_ns_name, + 1, nsid, 2, root, - 3, description, + 3, description, -1); - GNUNET_free (ns_name); + GNUNET_free (unique_ns_name); GNUNET_free_non_null (root); GNUNET_free (description); return GNUNET_OK; diff --git a/src/fs/gnunet-fs-gtk_namespace_manager.c b/src/fs/gnunet-fs-gtk_namespace_manager.c new file mode 100644 index 00000000..a7d79376 --- /dev/null +++ b/src/fs/gnunet-fs-gtk_namespace_manager.c @@ -0,0 +1,970 @@ +/* + This file is part of GNUnet + (C) 2005, 2006, 2010, 2012 Christian Grothoff (and other contributing authors) + + GNUnet 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, or (at your + option) any later version. + + GNUnet 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 GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/fs/gnunet-fs-gtk_namespace_manager.c + * @author LRN + */ +#include "gnunet-fs-gtk_common.h" +#include "gnunet-fs-gtk.h" +#include +#include + +struct GNUNET_GTK_NamespaceManagerContext +{ + GtkBuilder *builder; + GtkWidget *known_ns; + GtkWidget *ns_order; + GtkWidget *ns_details; + GtkTreeSelection *known_ns_sel; + GtkTreeSelection *ns_order_sel; + GtkTreeSelection *ns_details_sel; + GtkListStore *ns_order_store; + GtkListStore *known_ns_store; + GtkListStore *ns_details_store; + GtkWindow *namespace_manager; + GtkTreeViewColumn *order_rank; + GtkTreeViewColumn *order_name; + GtkTreeViewColumn *order_id; + GtkWidget *details_apply_button; + GtkWidget *details_delete_button; + int sort_direction; + struct GNUNET_CONTAINER_MetaData *uneditable_md; +}; + +/** + * THIS IS EVIL! Used to avoid opening more than one ns manager + * at once. Could be fixed by saving a pointer to the ns manager window + * somewhere in the main gnunet-fs-gtk window, but main window does + * not have a context structure for such things at the moment, hence + * this VERY EVIL GLOBAL VARIABLE! + */ +static struct GNUNET_GTK_NamespaceManagerContext *ns_manager = NULL; + +#define GNUNET_GTK_KNOWN_NAMESPACES_IS_MINE_COLUMN 0 +#define GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN 1 +#define GNUNET_GTK_KNOWN_NAMESPACES_NAME_COLUMN 2 +#define GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_COLUMN 3 +#define GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN 4 +#define GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN 5 +#define GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN 6 +#define GNUNET_GTK_KNOWN_NAMESPACES_NON_UNIQUE_NAME_COLUMN 7 + +#define GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN 0 +#define GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN 1 +#define GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN 2 +#define GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_BIN_COLUMN 3 +#define GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN 4 + +#define GNUNET_GTK_NAMESPACE_DETAILS_PLUGIN_NAME_COLUMN 0 +#define GNUNET_GTK_NAMESPACE_DETAILS_TYPE_BIN_COLUMN 1 +#define GNUNET_GTK_NAMESPACE_DETAILS_TYPE_COLUMN 2 +#define GNUNET_GTK_NAMESPACE_DETAILS_FORMAT_COLUMN 3 +#define GNUNET_GTK_NAMESPACE_DETAILS_DATA_MIME_COLUMN 4 +#define GNUNET_GTK_NAMESPACE_DETAILS_VALUE_COLUMN 5 + +static void +sort_order_list (struct GNUNET_GTK_NamespaceManagerContext *ctx, + int sort_column) +{ + int sorted = GNUNET_NO; + GtkTreeIter iter; + gint i; + gint row_count; + gint *row_indices, *row_ints; + gchar **row_strings; + + ctx->sort_direction = ctx->sort_direction <= 0 ? 1 : 0; + + row_count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL ( + ctx->ns_order_store), NULL); + if (TRUE != gtk_tree_model_get_iter_first (GTK_TREE_MODEL ( + ctx->ns_order_store), &iter)) + return; + + row_indices = g_new0 (gint, row_count); + row_ints = g_new0 (gint, row_count); + row_strings = g_new0 (gchar *, row_count); + + for (i = 0; i < row_count; i++) + { + int an_int; + char *a_string; + row_indices[i] = i; + switch (sort_column) + { + case GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN: + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &iter, + sort_column, &an_int, -1); + row_ints[i] = an_int; + row_strings[i] = NULL; + break; + case GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN: + case GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN: + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &iter, + sort_column, &a_string, -1); + row_strings[i] = a_string; + break; + default: + row_strings[i] = NULL; + break; + } + if (TRUE != gtk_tree_model_iter_next (GTK_TREE_MODEL ( + ctx->ns_order_store), &iter)) + break; + } + + while (sorted != GNUNET_YES) + { + sorted = GNUNET_YES; + for (i = 0; i < row_count - 1; i++) + { + int cmp_result; + + switch (sort_column) + { + case GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN: + cmp_result = row_ints[i] <= row_ints[i + 1] ? 0 : 1; + break; + case GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN: + case GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN: + /* FIXME: name can be UTF-8-encoded, use UTF-8-aware comparison func */ + cmp_result = strcmp (row_strings[i], row_strings[i + 1]); + break; + default: + break; + } + + if (((ctx->sort_direction <= 0) && (cmp_result <= 0)) || + ((ctx->sort_direction > 0) && (cmp_result > 0))) + { + int tmp_int, tmp_index; + char *tmp_string; + tmp_index = row_indices[i]; + tmp_int = row_ints[i]; + tmp_string = row_strings[i]; + row_indices[i] = row_indices[i + 1]; + row_ints[i] = row_ints[i + 1]; + row_strings[i] = row_strings[i + 1]; + row_ints[i + 1] = tmp_int; + row_strings[i + 1] = tmp_string; + row_indices[i + 1] = tmp_index; + sorted = GNUNET_NO; + } + } + } + + gtk_list_store_reorder (ctx->ns_order_store, row_indices); + + g_free (row_indices); + for (i = 0; i < row_count; i++) + g_free (row_strings[i]); + g_free (row_strings); + g_free (row_ints); +} + +void +GNUNET_GTK_namespace_manager_namespace_order_column_clicked_cb ( + GtkTreeViewColumn *treeviewcolumn, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + if (treeviewcolumn == ctx->order_rank) + { + sort_order_list (ctx, GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN); + } + else if (treeviewcolumn == ctx->order_name) + { + sort_order_list (ctx, GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN); + } + else if (treeviewcolumn == ctx->order_id) + { + sort_order_list (ctx, GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN); + } +} + +void +GNUNET_GTK_namespace_manager_known_namespaces_delete_button_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter; + GNUNET_HashCode *nsid; + GtkTreeRowReference *order_row, *known_row; + struct GNUNET_CONTAINER_MetaData *md; + + if (FALSE == gtk_tree_selection_get_selected (ctx->known_ns_sel, NULL, &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &nsid, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, &order_row, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, &md, + -1); + GNUNET_CONTAINER_meta_data_destroy (md); + gtk_list_store_remove (ctx->known_ns_store, &iter); + if (order_row != NULL) + { + if (GNUNET_OK == GNUNET_GTK_get_iter_from_reference (order_row, &iter)) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &iter, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, &known_row, -1); + gtk_list_store_remove (ctx->ns_order_store, &iter); + if (known_row != NULL) + gtk_tree_row_reference_free (known_row); + } + gtk_tree_row_reference_free (order_row); + } + GNUNET_free (nsid); + + gtk_list_store_clear (ctx->ns_details_store); + GNUNET_CONTAINER_meta_data_destroy (ctx->uneditable_md); + ctx->uneditable_md = NULL; +} + +void +GNUNET_GTK_namespace_manager_known_namespaces_swap_rank_button_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter known_iter, order_iter; + GNUNET_HashCode *nsid; + int32_t old_rank, new_rank; + GtkTreeRowReference *order_row, *known_row; + + if (FALSE == gtk_tree_selection_get_selected (ctx->known_ns_sel, NULL, &known_iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &nsid, + GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN, &old_rank, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, &order_row, + -1); + + if (old_rank == 0) + new_rank = -1; + else + new_rank = -old_rank; + + gtk_list_store_set (ctx->known_ns_store, &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN, new_rank, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, NULL, + -1); + + if (order_row != NULL) + { + if (new_rank < 0) + { + if (GNUNET_OK == GNUNET_GTK_get_iter_from_reference (order_row, &order_iter)) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &order_iter, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, &known_row, -1); + gtk_list_store_remove (ctx->ns_order_store, &order_iter); + if (known_row != NULL) + gtk_tree_row_reference_free (known_row); + } + } + gtk_tree_row_reference_free (order_row); + } + if (new_rank >= 0) + { + char *name, *identifier; + if (order_row != NULL) + { + /* This should not happen */ + GNUNET_break (0); + } + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_NAME_COLUMN, &name, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_COLUMN, &identifier, + -1); + known_row = GNUNET_GTK_get_reference_from_iter (GTK_TREE_MODEL ( + ctx->known_ns_store), &known_iter); + gtk_list_store_insert_with_values (ctx->ns_order_store, &order_iter, G_MAXINT, + GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN, new_rank, + GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN, name, + GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN, identifier, + GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_BIN_COLUMN, nsid, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, known_row, + -1); + g_free (name); + g_free (identifier); + order_row = GNUNET_GTK_get_reference_from_iter (GTK_TREE_MODEL (ctx->ns_order_store), + &order_iter); + gtk_list_store_set (ctx->known_ns_store, &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, order_row, -1); + } +} + +void +GNUNET_GTK_namespace_manager_namespace_order_apply_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter; + gint i; + gint row_count; + GtkTreeRowReference *known_row; + + row_count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL ( + ctx->ns_order_store), NULL); + if (TRUE != gtk_tree_model_get_iter_first (GTK_TREE_MODEL ( + ctx->ns_order_store), &iter)) + return; + + for (i = 0; i < row_count; i++) + { + gtk_list_store_set (ctx->ns_order_store, &iter, + GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN, i, -1); + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &iter, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, &known_row, -1); + if (known_row == NULL) + { + /* This is not supposed to happen. What to do? */ + GNUNET_break (0); + } + else + { + GtkTreeIter known_iter; + if (GNUNET_OK == GNUNET_GTK_get_iter_from_reference (known_row, &known_iter)) + { + gtk_list_store_set (ctx->known_ns_store, &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN, i, + -1); + } + } + if (TRUE != gtk_tree_model_iter_next (GTK_TREE_MODEL ( + ctx->ns_order_store), &iter)) + break; + } +} + +void +GNUNET_GTK_namespace_manager_namespace_details_add_button_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + /* FIXME: add a row to the details list. Disabled at the moment, since + * metadata type selection is not implemented. + */ +} + +void +GNUNET_GTK_namespace_manager_namespace_details_delete_button_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter; + + if (FALSE == gtk_tree_selection_get_selected (ctx->ns_details_sel, NULL, &iter)) + return; + + gtk_list_store_remove (ctx->ns_details_store, &iter); + gtk_widget_set_sensitive (ctx->details_apply_button, TRUE); +} + +void +GNUNET_GTK_namespace_manager_namespace_details_apply_button_clicked_cb ( + GtkButton *button, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter, known_iter; + gint i; + gint row_count; + struct GNUNET_CONTAINER_MetaData *md, *old_md; + char *plugin_name; + int type; + char *type_name; + int format; + char *data_mime_type; + char *data; + + row_count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL ( + ctx->ns_details_store), NULL); + if ((row_count > 0) && (TRUE != gtk_tree_model_get_iter_first ( + GTK_TREE_MODEL (ctx->ns_details_store), &iter))) + { + /* This should not happen */ + return; + } + + if (FALSE == gtk_tree_selection_get_selected (ctx->known_ns_sel, NULL, + &known_iter)) + { + /* This should not happen */ + return; + } + + md = GNUNET_CONTAINER_meta_data_create (); + + for (i = 0; i < row_count; i++) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_details_store), &iter, + GNUNET_GTK_NAMESPACE_DETAILS_PLUGIN_NAME_COLUMN, &plugin_name, + GNUNET_GTK_NAMESPACE_DETAILS_TYPE_BIN_COLUMN, &type, + GNUNET_GTK_NAMESPACE_DETAILS_TYPE_COLUMN, &type_name, + GNUNET_GTK_NAMESPACE_DETAILS_FORMAT_COLUMN, &format, + GNUNET_GTK_NAMESPACE_DETAILS_DATA_MIME_COLUMN, &data_mime_type, + GNUNET_GTK_NAMESPACE_DETAILS_VALUE_COLUMN, &data, + -1); + GNUNET_CONTAINER_meta_data_insert (md, plugin_name, + type, format, data_mime_type, data, strlen (data) + 1); + g_free (plugin_name); + g_free (type_name); + g_free (data_mime_type); + g_free (data); + if (TRUE != gtk_tree_model_iter_next (GTK_TREE_MODEL ( + ctx->ns_details_store), &iter)) + break; + } + GNUNET_CONTAINER_meta_data_merge (md, + (const struct GNUNET_CONTAINER_MetaData *) ctx->uneditable_md); + + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, &old_md, + -1); + GNUNET_CONTAINER_meta_data_destroy (old_md); + gtk_list_store_set (ctx->known_ns_store, &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, md, + -1); + gtk_widget_set_sensitive (ctx->details_apply_button, FALSE); +} + +void +GNUNET_GTK_namespace_manager_name_text_editing_started_cb ( + GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, + gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + + if (GTK_IS_ENTRY (editable)) + { + GtkTreePath *tree_path; + GtkTreeIter iter; + char *non_unique_name = NULL; + GtkEntry *entry = GTK_ENTRY (editable); + + tree_path = gtk_tree_path_new_from_string (path); + if (tree_path != NULL) + { + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ctx->known_ns_store), + &iter, tree_path)) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_NON_UNIQUE_NAME_COLUMN, &non_unique_name, + -1); + } + gtk_tree_path_free (tree_path); + } + if (non_unique_name == NULL) + { + gtk_cell_editable_editing_done (editable); + return; + } + gtk_entry_set_text (entry, non_unique_name); + g_free (non_unique_name); + } +} + +void +GNUNET_GTK_namespace_manager_name_text_edited_cb ( + GtkCellRendererText *renderer, gchar *path, gchar *new_text, + gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + char *unique_name; + GtkTreeRowReference *order_row; + + if (strlen (new_text) == 0) + return; + + GtkTreePath *tree_path; + GtkTreeIter iter; + tree_path = gtk_tree_path_new_from_string (path); + if (tree_path != NULL) + { + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ctx->known_ns_store), + &iter, tree_path)) + { + GNUNET_HashCode *nsid; + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &nsid, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, &order_row, + -1); + + unique_name = GNUNET_PSEUDONYM_name_uniquify ( + GNUNET_FS_GTK_get_configuration (), nsid, new_text, NULL); + + gtk_list_store_set (ctx->known_ns_store, &iter, + GNUNET_GTK_KNOWN_NAMESPACES_NON_UNIQUE_NAME_COLUMN, new_text, + GNUNET_GTK_KNOWN_NAMESPACES_NAME_COLUMN, unique_name, + -1); + + if (order_row != NULL) + { + GtkTreeIter order_iter; + if (GNUNET_OK == GNUNET_GTK_get_iter_from_reference (order_row, &order_iter)) + { + gtk_list_store_set (ctx->ns_order_store, &order_iter, + GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN, unique_name, + -1); + } + } + + GNUNET_free (unique_name); + } + gtk_tree_path_free (tree_path); + } +} + +void +GNUNET_GTK_namespace_manager_namespace_details_type_text_edited_cb ( + GtkCellRendererText *renderer, gchar *path, gchar *new_text, + gpointer user_data) +{ + /* Changing metadata type is more difficult than simply entering a + * new string, see publication editing dialog. So this is disabled + * for now. In fact, it's not going to be a Text renderer when it's done. + */ + /* + struct GNUNET_GTK_NamespaceManagerContext *ctx = cls; + GtkTreeIter iter; + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ctx->ns_details_store), + &iter, path)) + { + gtk_list_store_set (ctx->ns_details_store, &iter, + GNUNET_GTK_NAMESPACE_DETAILS_TYPE_COLUMN, new_text, + -1); + } + */ +} + +void +GNUNET_GTK_namespace_manager_namespace_details_value_text_edited_cb ( + GtkCellRendererText *renderer, gchar *path, gchar *new_text, + gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreePath *tree_path; + GtkTreeIter iter; + tree_path = gtk_tree_path_new_from_string (path); + if (tree_path != NULL) + { + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ctx->ns_details_store), + &iter, tree_path)) + { + char *old_text; + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_details_store), &iter, + GNUNET_GTK_NAMESPACE_DETAILS_VALUE_COLUMN, &old_text, + -1); + if (strcmp (old_text, new_text) != 0) + { + gtk_list_store_set (ctx->ns_details_store, &iter, + GNUNET_GTK_NAMESPACE_DETAILS_VALUE_COLUMN, new_text, + -1); + gtk_widget_set_sensitive (ctx->details_apply_button, TRUE); + } + g_free (old_text); + } + gtk_tree_path_free (tree_path); + } +} + +/** + * Iterator over all known pseudonyms. + * Populate "known ns" and "ns order" lists. + * + * @param cls closure + * @param pseudonym hash code of public key of pseudonym + * @param md meta data known about the pseudonym + * @param rating the local rating of the pseudonym + * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort + */ +static int +populate_known_ns_list (void *cls, const GNUNET_HashCode *pseudonym, + const char *name, const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = cls; + GNUNET_HashCode *nsid; + struct GNUNET_CRYPTO_HashAsciiEncoded identifier; + GtkTreeIter known_iter, order_iter; + struct GNUNET_CONTAINER_MetaData *md_copy; + char *non_null_name, *non_null_unique_name; + + nsid = GNUNET_malloc (sizeof (GNUNET_HashCode)); + *nsid = *pseudonym; + + GNUNET_CRYPTO_hash_to_enc (nsid, &identifier); + + GNUNET_PSEUDONYM_get_info (GNUNET_FS_GTK_get_configuration (), + nsid, NULL, NULL, &non_null_name, NULL); + non_null_unique_name = GNUNET_PSEUDONYM_name_uniquify ( + GNUNET_FS_GTK_get_configuration (), nsid, non_null_name, NULL); + + md_copy = GNUNET_CONTAINER_meta_data_duplicate (md); + + gtk_list_store_insert_with_values (ctx->known_ns_store, &known_iter, G_MAXINT, + GNUNET_GTK_KNOWN_NAMESPACES_IS_MINE_COLUMN, FALSE, + GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN, rating, + GNUNET_GTK_KNOWN_NAMESPACES_NAME_COLUMN, non_null_unique_name, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_COLUMN, identifier.encoding, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, nsid, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, NULL, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, md_copy, + GNUNET_GTK_KNOWN_NAMESPACES_NON_UNIQUE_NAME_COLUMN, non_null_name, + -1); + + if (rating >= 0) + { + GtkTreeRowReference *rr = GNUNET_GTK_get_reference_from_iter (GTK_TREE_MODEL ( + ctx->known_ns_store), &known_iter); + gtk_list_store_insert_with_values (ctx->ns_order_store, &order_iter, G_MAXINT, + GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN, rating, + GNUNET_GTK_NAMESPACE_ORDER_NAME_COLUMN, non_null_unique_name, + GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_COLUMN, identifier.encoding, + GNUNET_GTK_NAMESPACE_ORDER_IDENTIFIER_BIN_COLUMN, nsid, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, rr, + -1); + rr = GNUNET_GTK_get_reference_from_iter (GTK_TREE_MODEL (ctx->ns_order_store), + &order_iter); + gtk_list_store_set (ctx->known_ns_store, &known_iter, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, rr, -1); + } + GNUNET_free (non_null_name); + GNUNET_free (non_null_unique_name); + + return GNUNET_OK; +} + +static void +apply_known_ns_changes (struct GNUNET_GTK_NamespaceManagerContext *ctx) +{ + GtkTreeIter iter; + gint i; + gint row_count; + GNUNET_HashCode *nsid; + char *name; + int32_t rank; + struct GNUNET_CONTAINER_MetaData *md; + + row_count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL ( + ctx->known_ns_store), NULL); + if (TRUE != gtk_tree_model_get_iter_first (GTK_TREE_MODEL ( + ctx->known_ns_store), &iter)) + return; + + for (i = 0; i < row_count; i++) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &nsid, + GNUNET_GTK_KNOWN_NAMESPACES_NON_UNIQUE_NAME_COLUMN, &name, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, &md, + GNUNET_GTK_KNOWN_NAMESPACES_RANK_COLUMN, &rank, + -1); + GNUNET_PSEUDONYM_set_info (GNUNET_FS_GTK_get_configuration (), + nsid, name, md, rank); + g_free (name); + if (TRUE != gtk_tree_model_iter_next (GTK_TREE_MODEL ( + ctx->known_ns_store), &iter)) + break; + } +} + +static void +free_lists_contents (struct GNUNET_GTK_NamespaceManagerContext *ctx) +{ + GtkTreeIter iter; + gint i; + gint row_count; + GNUNET_HashCode *nsid; + GtkTreeRowReference *order_row; + struct GNUNET_CONTAINER_MetaData *md; + + row_count = gtk_tree_model_iter_n_children (GTK_TREE_MODEL ( + ctx->known_ns_store), NULL); + if (TRUE != gtk_tree_model_get_iter_first (GTK_TREE_MODEL ( + ctx->known_ns_store), &iter)) + return; + + for (i = 0; i < row_count; i++) + { + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &nsid, + GNUNET_GTK_KNOWN_NAMESPACES_ORDER_ROW_REFERENCE_COLUMN, &order_row, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, &md, + -1); + if (order_row != NULL) + { + GtkTreeIter order_iter; + if (GNUNET_OK == GNUNET_GTK_get_iter_from_reference (order_row, &order_iter)) + { + GtkTreeRowReference *known_row; + gtk_tree_model_get (GTK_TREE_MODEL (ctx->ns_order_store), &order_iter, + GNUNET_GTK_NAMESPACE_ORDER_KNOWN_ROW_REFERENCE_COLUMN, &known_row, + -1); + if (known_row != NULL) + gtk_tree_row_reference_free (known_row); + } + gtk_tree_row_reference_free (order_row); + } + GNUNET_CONTAINER_meta_data_destroy (md); + GNUNET_free (nsid); + if (TRUE != gtk_tree_model_iter_next (GTK_TREE_MODEL ( + ctx->known_ns_store), &iter)) + break; + } + + gtk_list_store_clear (ctx->ns_order_store); + gtk_list_store_clear (ctx->known_ns_store); + gtk_list_store_clear (ctx->ns_details_store); + if (ctx->uneditable_md != NULL) + GNUNET_CONTAINER_meta_data_destroy (ctx->uneditable_md); +} + +void +GNUNET_GTK_namespace_manager_dialog_response_cb (GtkDialog *dialog, + gint response_id, gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + switch (response_id) + { + case GTK_RESPONSE_APPLY: + case GTK_RESPONSE_OK: + apply_known_ns_changes (ctx); + break; + default: + break; + } + switch (response_id) + { + case GTK_RESPONSE_APPLY: + break; + case GTK_RESPONSE_OK: + case GTK_RESPONSE_CANCEL: + default: + free_lists_contents (ctx); + gtk_widget_destroy (GTK_WIDGET (ctx->namespace_manager)); + GNUNET_free (ctx); + ns_manager = NULL; + } +} + + +static gboolean +mark_as_mine (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer data) +{ + const GNUNET_HashCode *mine_id = data; + const GNUNET_HashCode *ns_id; + + gtk_tree_model_get (model, iter, + GNUNET_GTK_KNOWN_NAMESPACES_IDENTIFIER_BIN_COLUMN, &ns_id, -1); + + if (memcmp (ns_id, mine_id, sizeof (GNUNET_HashCode)) != 0) + return FALSE; + + gtk_list_store_set (GTK_LIST_STORE (model), iter, + GNUNET_GTK_KNOWN_NAMESPACES_IS_MINE_COLUMN, TRUE, -1); + return TRUE; +} + +/** + * Callback with information about local (!) namespaces. + * Contains the names of the local namespace and the global + * ID. + * + * @param cls closure + * @param name human-readable identifier of the namespace + * @param id hash identifier for the namespace + */ +static void +mark_namespaces_as_mine (void *cls, const char *name, + const GNUNET_HashCode * id) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = cls; + + gtk_tree_model_foreach (GTK_TREE_MODEL (ctx->known_ns_store), mark_as_mine, + (gpointer) id); +} + +/** + * Type of a function that libextractor calls for each + * meta data item found. + * + * @param cls closure (user-defined) + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 to continue extracting, 1 to abort + */ +static int +populate_details_list (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = cls; + const char *type_name; + char *data_utf8; + + if (format == EXTRACTOR_METAFORMAT_UTF8 || + format == EXTRACTOR_METAFORMAT_C_STRING) + { + type_name = EXTRACTOR_metatype_to_string (type); + /* TODO: translate type_name using dgettext? */ + data_utf8 = GNUNET_FS_GTK_dubious_meta_to_utf8 (format, data, data_len); + if (data != NULL) + { + gtk_list_store_insert_with_values (ctx->ns_details_store, NULL, G_MAXINT, + GNUNET_GTK_NAMESPACE_DETAILS_PLUGIN_NAME_COLUMN, plugin_name, + GNUNET_GTK_NAMESPACE_DETAILS_TYPE_BIN_COLUMN, type, + GNUNET_GTK_NAMESPACE_DETAILS_TYPE_COLUMN, type_name, + GNUNET_GTK_NAMESPACE_DETAILS_FORMAT_COLUMN, + EXTRACTOR_METAFORMAT_UTF8, + GNUNET_GTK_NAMESPACE_DETAILS_DATA_MIME_COLUMN, data_mime_type, + GNUNET_GTK_NAMESPACE_DETAILS_VALUE_COLUMN, data_utf8, + -1); + GNUNET_free (data_utf8); + return 0; + } + } + GNUNET_CONTAINER_meta_data_insert (ctx->uneditable_md, + plugin_name, type, format, data_mime_type, data, data_len); + return 0; +} + +static void +ns_details_selection_changed (GtkTreeSelection *treeselection, + gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter; + + if (FALSE == gtk_tree_selection_get_selected (ctx->ns_details_sel, NULL, &iter)) + { + gtk_widget_set_sensitive (ctx->details_delete_button, FALSE); + return; + } + + gtk_widget_set_sensitive (ctx->details_delete_button, TRUE); +} + +static void +known_ns_selection_changed (GtkTreeSelection *treeselection, + gpointer user_data) +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx = user_data; + GtkTreeIter iter; + const struct GNUNET_CONTAINER_MetaData *md; + + if (FALSE == gtk_tree_selection_get_selected (ctx->known_ns_sel, NULL, &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (ctx->known_ns_store), &iter, + GNUNET_GTK_KNOWN_NAMESPACES_METADATA_COLUMN, &md, + -1); + if (ctx->uneditable_md != NULL) + GNUNET_CONTAINER_meta_data_clear (ctx->uneditable_md); + else + ctx->uneditable_md = GNUNET_CONTAINER_meta_data_create (); + gtk_list_store_clear (ctx->ns_details_store); + gtk_widget_set_sensitive (ctx->details_apply_button, FALSE); + GNUNET_CONTAINER_meta_data_iterate ((const struct GNUNET_CONTAINER_MetaData *) md, + populate_details_list, ctx); + gtk_widget_set_sensitive (ctx->details_apply_button, FALSE); +} + +void +GNUNET_GTK_namespace_manager_open () +{ + struct GNUNET_GTK_NamespaceManagerContext *ctx; + + if (ns_manager != NULL) + return; + + ctx = GNUNET_malloc (sizeof (struct GNUNET_GTK_NamespaceManagerContext)); + ctx->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_namespace_manager.glade", ctx); + if (ctx->builder == NULL) + { + GNUNET_break (0); + GNUNET_free (ctx); + return; + } + + /* initialize widget references */ + ctx->known_ns = GTK_WIDGET (gtk_builder_get_object (ctx->builder, + "GNUNET_GTK_namespace_manager_known_treeview")); + ctx->ns_order = GTK_WIDGET (gtk_builder_get_object (ctx->builder, + "GNUNET_GTK_namespace_manager_namespace_order_treeview")); + ctx->ns_details = GTK_WIDGET (gtk_builder_get_object (ctx->builder, + "GNUNET_GTK_namespace_manager_namespace_details_treeview")); + ctx->known_ns_sel = gtk_tree_view_get_selection (GTK_TREE_VIEW ( + ctx->known_ns)); + ctx->ns_order_sel = gtk_tree_view_get_selection (GTK_TREE_VIEW ( + ctx->ns_order)); + ctx->ns_details_sel = gtk_tree_view_get_selection (GTK_TREE_VIEW ( + ctx->ns_details)); + ctx->ns_order_store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (ctx->ns_order))); + ctx->known_ns_store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (ctx->known_ns))); + ctx->ns_details_store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (ctx->ns_details))); + ctx->namespace_manager = GTK_WINDOW (gtk_builder_get_object ( + ctx->builder, "GNUNET_GTK_namespace_manager_dialog")); + ctx->details_apply_button = GTK_WIDGET (gtk_builder_get_object (ctx->builder, + "GNUNET_GTK_namespace_manager_namespace_details_apply_button")); + ctx->details_delete_button = GTK_WIDGET (gtk_builder_get_object (ctx->builder, + "GNUNET_GTK_namespace_manager_namespace_details_delete_button")); + ctx->order_rank = gtk_tree_view_get_column (GTK_TREE_VIEW (ctx->ns_order), 0); + ctx->order_name = gtk_tree_view_get_column (GTK_TREE_VIEW (ctx->ns_order), 1); + ctx->order_id = gtk_tree_view_get_column (GTK_TREE_VIEW (ctx->ns_order), 2); + + /* connect signals; FIXME-GTK3: these could be connected with (modern) Glade */ + g_signal_connect (G_OBJECT (ctx->known_ns_sel), "changed", + G_CALLBACK (known_ns_selection_changed), ctx); + g_signal_connect (G_OBJECT (ctx->ns_details_sel), "changed", + G_CALLBACK (ns_details_selection_changed), ctx); + + /* populate namespace model */ + (void) GNUNET_PSEUDONYM_list_all (GNUNET_FS_GTK_get_configuration (), + populate_known_ns_list, ctx); + + /* mark our own namespaces as such */ + GNUNET_FS_namespace_list (GNUNET_FS_GTK_get_fs_handle (), + mark_namespaces_as_mine, ctx); + + /* sort namespace order list by rank (initially) */ + sort_order_list (ctx, GNUNET_GTK_NAMESPACE_ORDER_RANK_COLUMN); + + ns_manager = ctx; + + gtk_widget_set_sensitive (ctx->details_apply_button, FALSE); + + /* show dialog */ + gtk_window_present (GTK_WINDOW (ctx->namespace_manager)); +} + +/* end of gnunet-fs-gtk_namespace_manager.c */ -- cgit v1.2.3