/* This file is part of GNUnet (C) 2005, 2006, 2010 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-edit_publish_dialog.c * @author Christian Grothoff */ #include "gnunet-fs-gtk-common.h" #include "gnunet-fs-gtk-edit_publish_dialog.h" #include "gnunet-fs-gtk.h" #include #include "metatypes.c" /** * Internal state kept for each "edit" dialog where the user can edit * publishing information for a file. */ struct EditPublicationDialogContext { /** * Builder for the dialog. */ GtkBuilder *builder; /** * The 'window' object for the dialog. */ GtkWindow *edit_publication_window; /** * The confirmation button which closes the dialog (only sensitive * if the values entered are valid). */ GtkWidget *confirm_button; /** * Tree view showing the meta data for the file. */ GtkTreeView *meta_treeview; /** * Tree view showing the keywords for the file. */ GtkTreeView *keywords_treeview; /** * Image showing the preview image for the file. */ GtkImage *preview_image; /** * Combo box where the user can select the anonymity level. */ GtkComboBox *anonymity_combo; /** * Liststore of the 'anonymity_combo' with the anonymity levels. */ GtkListStore *anonymity_liststore; /** * Liststore of possible publication types. */ GtkListStore *pubtypes_liststore; /** * Liststore of all possible meta types the user can choose from. * (updated to based on the selected publication type). */ GtkListStore *metatypes_liststore; /** * Liststore showing the meta data of the file (associated with * the 'meta_treeview'. */ GtkListStore *meta_liststore; /** * Liststore with the keywords of the file (associated with the * 'keywords_treeview'. */ GtkListStore *keywords_liststore; /** * Spin button to select content priority level for the file. */ GtkSpinButton *priority_spin; /** * Spin button to select the expiration year. */ GtkSpinButton *expiration_year_spin; /** * Spin button to select the replication level. */ GtkSpinButton *replication_spin; /** * Entry line for adding additional keywords. */ GtkEntry *keyword_entry; /** * Entry line for setting a namespace root (possibly invisible). */ GtkEntry *root_entry; /** * Entry line to check indexing vs. inserting (possibly invisible) */ GtkToggleButton *index_checkbutton; /** * ??? */ GtkTreeIter *meta_combo_selected_iter; /** * Continuation to call once the dialog has been closed */ GNUNET_FS_GTK_EditPublishDialogCallback cb; /** * Closure for 'cb'. */ void *cb_cls; /** * Short name of the file being published (or NULL). */ char *short_fn; /** * Briefly used temporary meta data set. */ struct GNUNET_CONTAINER_MetaData *md; /** * Information about the file being published as seen by the FS-API. * This is what we are primarily editing. */ struct GNUNET_FS_FileInformation *fip; /** * Overall options for the publish operation. This is also what * we are primarily editing. */ struct GNUNET_FS_BlockOptions bo; /** * Flag to track if we changed the preview and thus should keep/discard * certain metadata. (FIXME: yucky!) */ int preview_changed; /** * Is this operation for a directory? */ int is_directory; /** * Is it allowed for the user to supply keywords in this dialog? * FIXME: why 'gboolean'? */ gboolean allow_no_keywords; }; /** * Free resources associated with the edit publication dialog. * * @param ctx the context of the dialog to release resources of */ static void free_edit_dialog_context (struct EditPublicationDialogContext *ctx) { gtk_widget_destroy (GTK_WIDGET (ctx->edit_publication_window)); GNUNET_free_non_null (ctx->short_fn); // FIXME-LEAK: destroy builder! GNUNET_free (ctx); } /* ****************** metadata editing ******************** */ /** * Update the set of metatypes listed in the dialog based on the * given code. * * @param ctx main dialog context * @param code which set of metatypes is desired? */ static void change_metatypes (struct EditPublicationDialogContext *ctx, gint code) { gint pubtype_count; gint max_type; gint i; GtkTreeIter iter; /* double-check that 'code' is valid */ for (pubtype_count = 0; NULL != types[pubtype_count]; pubtype_count++) ; GNUNET_assert (code < pubtype_count); /* clear existing selection of metatypes */ gtk_list_store_clear (ctx->metatypes_liststore); max_type = EXTRACTOR_metatype_get_max (); /* add new types based on selection */ for (i = 0; types[code][i] != EXTRACTOR_METATYPE_RESERVED; i++) if ( (types[code][i] < max_type) && (types[code][i] > 0) ) gtk_list_store_insert_with_values (ctx->metatypes_liststore, &iter, G_MAXINT, 0, types[code][i], 1, EXTRACTOR_METAFORMAT_UTF8, 2, EXTRACTOR_metatype_to_string (types [code][i]), 3, EXTRACTOR_metatype_to_description (types[code][i]), -1); } /** * The user has selected a different publication type. * Update the meta type selection. * * @param widget the publication type combo box widget * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_type_combo_changed_cb (GtkComboBox * widget, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeIter iter; gint code; if (! gtk_combo_box_get_active_iter (widget, &iter)) return; gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, &code, -1); change_metatypes (ctx, code); } /** * The user has changed the selection in the meta data tree view. * Update the sensitivity of the 'delete' button. * * @param ts the tree selection object * @param user_data the 'struct EditPublicationDialogContext' */ /* FIXME: connect this signal via glade (modern versions of Glade support this) */ static void metadata_selection_changed_cb (GtkTreeSelection *ts, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_delete_button")), gtk_tree_selection_get_selected (ts, NULL, NULL)); } void GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_edited_cb (GtkCellRendererText * renderer, gchar * path, gchar * new_text, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeModel *combo_model; GtkTreeIter iter; gint type_id; gchar *description = NULL; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ctx->meta_liststore), &iter, path)) return; if (!ctx->meta_combo_selected_iter) return; g_object_get (GTK_CELL_RENDERER_COMBO (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer")), "model", &combo_model, NULL); gtk_tree_model_get (combo_model, ctx->meta_combo_selected_iter, 0, &type_id, 2, &description, -1); g_object_unref (combo_model); g_free (ctx->meta_combo_selected_iter); ctx->meta_combo_selected_iter = NULL; gtk_list_store_set (ctx->meta_liststore, &iter, 0, type_id, 1, EXTRACTOR_METAFORMAT_UTF8, 2, new_text, 4, description, -1); g_free (description); } void GNUNET_GTK_edit_publication_metadata_tree_view_type_renderer_changed_cb (GtkCellRendererCombo * combo, gchar * path_string, GtkTreeIter * new_iter, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; if (ctx->meta_combo_selected_iter) g_free (ctx->meta_combo_selected_iter); ctx->meta_combo_selected_iter = g_new0 (GtkTreeIter, 1); *ctx->meta_combo_selected_iter = *new_iter; } void GNUNET_GTK_edit_publication_metadata_tree_view_value_renderer_edited_cb (GtkCellRendererText * renderer, gchar * path, gchar * new_text, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeIter iter; gint metatype; char *avalue; const char *ivalue; size_t slen; char *pos; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ctx->meta_liststore), &iter, path)) return; gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, &metatype, -1); if (metatype == EXTRACTOR_METATYPE_FILENAME && new_text[strlen (new_text) - 1] != '/' && ctx->is_directory) { GNUNET_asprintf (&avalue, "%s/", new_text); /* if user typed '\' instead of '/', change it! */ slen = strlen (avalue); while ((slen > 1) && (avalue[slen - 2] == '\\')) { avalue[slen - 2] = '/'; avalue[slen - 1] = '\0'; slen--; } while (NULL != (pos = strstr (avalue, "\\"))) *pos = '/'; // remove '../' everywhere while (NULL != (pos = strstr (avalue, "../"))) { pos[0] = '_'; pos[1] = '_'; pos[2] = '_'; } ivalue = avalue; } else { ivalue = new_text; avalue = NULL; } gtk_list_store_set (ctx->meta_liststore, &iter, 3, ivalue, -1); GNUNET_free_non_null (avalue); } /** * The user has pushed the 'add' button for metadata. Add a 'dummy' value * to our meta data store (to be edited by the user). * * @param button the 'add' button * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_add_button_clicked_cb (GtkButton * button, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeIter iter; gtk_list_store_insert_with_values (ctx->meta_liststore, &iter, 0, 0, 0, 1, EXTRACTOR_METAFORMAT_UTF8, 2, _("Select a type"), 3, _("Specify a value"), 4, NULL, -1); } /** * The user has pushed the 'del' button for metadata. * If there is a metadata selected, remove it from the list store. * * @param widget the button * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_delete_button_clicked_cb (GtkButton * button, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeIter iter; GtkTreeSelection *meta_selection; meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview); if (! gtk_tree_selection_get_selected (meta_selection, NULL, &iter)) { GNUNET_break (0); return; } GNUNET_break (gtk_list_store_remove (ctx->meta_liststore, &iter)); gtk_tree_selection_select_iter (meta_selection, &iter); } /** * The user has selected another preview image file. Update the * preview image. * * @param widget the file chooser dialog that completed * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button_file_set_cb (GtkFileChooserButton * widget, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; gchar *fn; fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget)); gtk_image_set_from_file (ctx->preview_image, fn); g_free (fn); ctx->preview_changed = GNUNET_YES; } /* ****************** keyword list editing ******************** */ /** * The user has changed the selection in the keyword tree view. * Update the sensitivity of the 'delete' button. * * @param ts the tree selection object * @param user_data the 'struct EditPublicationDialogContext' */ /* FIXME: connect this signal via glade (modern versions of Glade support this) */ static void keywords_selection_changed_cb (GtkTreeSelection *ts, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_keyword_list_del_button")), gtk_tree_selection_get_selected (ts, NULL, NULL)); } /** * The user has edited the keyword entry line. Update the * sensitivity of the 'add' button. * * @param editable the entry line for keywords * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_keyword_entry_changed_cb (GtkEditable * editable, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; const char *keyword; keyword = gtk_entry_get_text (ctx->keyword_entry); gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_keyword_list_add_button")), (strlen (keyword) > 0) ? TRUE : FALSE); } /** * The user has pushed the 'del' button for the keyword. * If there is a keyword selected, remove it from the list store. * * @param widget the button * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_keyword_list_del_button_clicked_cb (GtkButton * button, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; GtkTreeIter iter; GtkTreeSelection *keywords_selection; keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview); if (! gtk_tree_selection_get_selected (keywords_selection, NULL, &iter)) { GNUNET_break (0); return; } GNUNET_break (gtk_list_store_remove (GTK_LIST_STORE (ctx->keywords_liststore), &iter)); gtk_tree_selection_select_iter (keywords_selection, &iter); /* disable confirm button if keywords are required and we have no more keywords */ if ( (! ctx->allow_no_keywords) && (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->keywords_liststore), &iter)) ) gtk_widget_set_sensitive (ctx->confirm_button, FALSE); } /** * The user has pushed the 'add' button for the keyword (or pressed RETURN). * If there is a keyword in the line, add it to the list store. * * @param widget the entry line, or NULL (if we are called from 'RETURN') * @param user_data the 'struct EditPublicationDialogContext' */ void GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (GtkButton * button, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; const char *keyword; GtkTreeIter iter; keyword = gtk_entry_get_text (ctx->keyword_entry); if (strlen (keyword) == 0) return; gtk_list_store_insert_with_values (ctx->keywords_liststore, &iter, G_MAXINT, 0, keyword, 1, TRUE, -1); gtk_widget_set_sensitive (ctx->confirm_button, TRUE); gtk_entry_set_text (ctx->keyword_entry, ""); } /** * The user has pushed a button in the entry line. Check if it was 'RETURN' * and if so consider executing the 'add' action. * * @param widget the entry line * @param event the event information * @param user_data the 'struct EditPublicationDialogContext' */ gboolean GNUNET_GTK_edit_publication_keyword_entry_key_press_event_cb (GtkWidget * widget, GdkEventKey * event, gpointer user_data) { struct EditPublicationDialogContext *ctx = user_data; if (event->keyval != GDK_KEY_Return) return FALSE; GNUNET_GTK_edit_publication_keyword_list_add_button_clicked_cb (NULL, ctx); return TRUE; } /* ****************** handlers for closing the dialog ******************** */ /** * Copy binary meta data from to the new container and also * preserve all entries that were not changed. * * @param cls closure, a 'struct FileInformationUpdateContext' * @param plugin_name name of the plugin that produced this value; * special values can be used (i.e. '' 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 */ static int preserve_meta_items (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 EditPublicationDialogContext *ctx = cls; GtkTreeIter iter; gchar *value; guint ntype; guint nformat; int keep; keep = GNUNET_NO; switch (format) { case EXTRACTOR_METAFORMAT_UTF8: case EXTRACTOR_METAFORMAT_C_STRING: if (TRUE == gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->meta_liststore), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, &ntype, 1, &nformat, 3, &value, -1); if ((ntype == type) && (nformat == format) && (0 == strcmp (value, data))) { gtk_list_store_remove (ctx->meta_liststore, &iter); keep = GNUNET_YES; g_free (value); break; } g_free (value); } while (TRUE == gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->meta_liststore), &iter)); } break; case EXTRACTOR_METAFORMAT_UNKNOWN: break; case EXTRACTOR_METAFORMAT_BINARY: if (ctx->preview_changed == GNUNET_NO) keep = GNUNET_YES; break; default: GNUNET_break (0); break; } if (GNUNET_YES == keep) GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_meta_data_insert (ctx->md, plugin_name, type, format, data_mime_type, data, data_len)); return 0; } /** * Function called to update the information in FI. * * @param cls closure with a 'struct FileInformationUpdateContext *' * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options (can be modified) * @param do_index should we index (can be modified) * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_SYSERR (aborts after first call) */ static int file_information_update (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct EditPublicationDialogContext *ctx = cls; GtkTreeIter iter; struct GNUNET_FS_Uri *nxt; struct GNUNET_FS_Uri *mrg; gchar *value; guint ntype; guint nformat; gchar *fn; char *data; gsize data_size; const char *mime; GFile *f; GFileInfo *finfo; char *sfn; if (!GNUNET_GTK_get_selected_anonymity_combo_level (ctx->anonymity_combo, &ctx->bo.anonymity_level)) return GNUNET_SYSERR; ctx->bo.content_priority = gtk_spin_button_get_value (ctx->priority_spin); ctx->bo.replication_level = gtk_spin_button_get_value (ctx->replication_spin); *do_index = gtk_toggle_button_get_active (ctx->index_checkbutton); ctx->bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (ctx->expiration_year_spin); /* update URI */ if (NULL != (*uri)) GNUNET_FS_uri_destroy (*uri); *uri = NULL; nxt = NULL; mrg = NULL; if (TRUE == gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->keywords_liststore), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (ctx->keywords_liststore), &iter, 0, &value, -1); nxt = GNUNET_FS_uri_ksk_create_from_args (1, (const char **) &value); mrg = GNUNET_FS_uri_ksk_merge (nxt, *uri); GNUNET_FS_uri_destroy (nxt); if (NULL != *uri) GNUNET_FS_uri_destroy (*uri); *uri = mrg; g_free (value); } while (TRUE == gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->keywords_liststore), &iter)); } /* update meta */ ctx->md = GNUNET_CONTAINER_meta_data_create (); GNUNET_CONTAINER_meta_data_iterate (meta, &preserve_meta_items, ctx); GNUNET_CONTAINER_meta_data_clear (meta); if (TRUE == gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ctx->meta_liststore), &iter)) { do { gtk_tree_model_get (GTK_TREE_MODEL (ctx->meta_liststore), &iter, 0, &ntype, 1, &nformat, 3, &value, -1); if (ntype > 0) GNUNET_CONTAINER_meta_data_insert (ctx->md, "", ntype, nformat, "text/plain", value, strlen (value) + 1); g_free (value); } while (TRUE == gtk_tree_model_iter_next (GTK_TREE_MODEL (ctx->meta_liststore), &iter)); } GNUNET_CONTAINER_meta_data_merge (meta, ctx->md); if (ctx->preview_changed == GNUNET_YES) { fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_metadata_preview_file_chooser_button"))); f = g_file_new_for_path (fn); finfo = g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, NULL); if (FALSE == g_file_load_contents (f, NULL, &data, &data_size, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not load preview `%s' into memory\n"), fn); } else { mime = g_file_info_get_attribute_string (finfo, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_THUMBNAIL, EXTRACTOR_METAFORMAT_BINARY, mime, data, data_size); } g_object_unref (finfo); g_object_unref (f); g_free (fn); } GNUNET_CONTAINER_meta_data_destroy (ctx->md); ctx->md = NULL; /* update short_fn */ sfn = GNUNET_CONTAINER_meta_data_get_first_by_types (meta, EXTRACTOR_METATYPE_FILENAME, -1); if (NULL != sfn) { GNUNET_free_non_null (ctx->short_fn); ctx->short_fn = sfn; } return GNUNET_SYSERR; /* only visit top-level item */ } void GNUNET_GTK_edit_publication_cancel_button_clicked_cb (GtkButton * button, struct EditPublicationDialogContext *ctx) { int do_index; /* FIXME: why are we passing half of these values here? */ do_index = gtk_toggle_button_get_active (ctx->index_checkbutton); ctx->cb (ctx->cb_cls, do_index, ctx->short_fn, &ctx->bo, NULL, GTK_RESPONSE_CANCEL); free_edit_dialog_context (ctx); } void GNUNET_GTK_edit_publication_confirm_button_clicked_cb (GtkButton * button, struct EditPublicationDialogContext *ctx) { gint year; const char *root; int do_index; GNUNET_FS_file_information_inspect (ctx->fip, &file_information_update, ctx); if (!GNUNET_GTK_get_selected_anonymity_combo_level (ctx->anonymity_combo, &ctx->bo.anonymity_level)) ctx->bo.content_priority = gtk_spin_button_get_value (ctx->priority_spin); ctx->bo.replication_level = gtk_spin_button_get_value (ctx->replication_spin); do_index = gtk_toggle_button_get_active (ctx->index_checkbutton); year = gtk_spin_button_get_value (ctx->expiration_year_spin); ctx->bo.expiration_time = GNUNET_FS_year_to_time (year); root = gtk_entry_get_text (ctx->root_entry); ctx->cb (ctx->cb_cls, do_index, ctx->short_fn, &ctx->bo, root, GTK_RESPONSE_OK); free_edit_dialog_context (ctx); } gboolean GNUNET_GTK_edit_publication_window_delete_event_cb (GtkWidget * widget, GdkEvent * event, struct EditPublicationDialogContext *ctx) { GNUNET_GTK_edit_publication_cancel_button_clicked_cb (GTK_BUTTON (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_cancel_button")), ctx); return TRUE; } /* ****************** code for initialization of the dialog ******************** */ /** * Add each of the keywords to the keyword list store. * * @param cls closure * @param keyword the keyword * @param is_mandatory is the keyword mandatory (in a search) * @return GNUNET_OK to continue to iterate */ static int add_keyword (void *cls, const char *keyword, int is_mandatory) { GtkListStore *ls; GtkTreeIter iter; ls = GTK_LIST_STORE (cls); gtk_list_store_insert_with_values (ls, &iter, G_MAXINT, 0, keyword, 1, FALSE, -1); return GNUNET_OK; } /** * Function called to extract the information from FI. * * @param cls closure * @param fi the entry in the publish-structure * @param length length of the file or directory * @param meta metadata for the file or directory (can be modified) * @param uri pointer to the keywords that will be used for this entry (can be modified) * @param bo block options * @param do_index should we index (can be modified) * @param client_info pointer to client context set upon creation (can be modified) * @return GNUNET_SYSERR (aborts after first call) */ static int file_information_extract (void *cls, struct GNUNET_FS_FileInformation *fi, uint64_t length, struct GNUNET_CONTAINER_MetaData *meta, struct GNUNET_FS_Uri **uri, struct GNUNET_FS_BlockOptions *bo, int *do_index, void **client_info) { struct EditPublicationDialogContext *ctx = cls; GdkPixbuf *pixbuf; int year; if (NULL != *uri) GNUNET_FS_uri_ksk_get_keywords (*uri, &add_keyword, ctx->keywords_liststore); if (NULL != meta) { GNUNET_CONTAINER_meta_data_iterate (meta, &GNUNET_FS_GTK_add_meta_data_to_list_store, ctx->meta_liststore); pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta); if (pixbuf != NULL) { gtk_image_set_from_pixbuf (ctx->preview_image, pixbuf); } } year = (int) GNUNET_FS_time_to_year (ctx->bo.expiration_time); gtk_spin_button_set_value (ctx->expiration_year_spin, year); GNUNET_GTK_select_anonymity_combo_level (ctx->anonymity_combo, ctx->bo.anonymity_level); gtk_spin_button_set_value (ctx->priority_spin, ctx->bo.content_priority); gtk_spin_button_set_value (ctx->replication_spin, ctx->bo.replication_level); gtk_toggle_button_set_active (ctx->index_checkbutton, *do_index); return GNUNET_SYSERR; /* only visit top-level item */ } void GNUNET_GTK_edit_publication_window_realize_cb (GtkWidget *widget, struct EditPublicationDialogContext *ctx) { GtkTreeSelection *meta_selection; GtkTreeSelection *keywords_selection; /* FIXME: these can be set by (modern) versions of Glade */ keywords_selection = gtk_tree_view_get_selection (ctx->keywords_treeview); meta_selection = gtk_tree_view_get_selection (ctx->meta_treeview); g_signal_connect (G_OBJECT (keywords_selection), "changed", G_CALLBACK (keywords_selection_changed_cb), ctx); g_signal_connect (G_OBJECT (meta_selection), "changed", G_CALLBACK (metadata_selection_changed_cb), ctx); } /** * Open the dialog to edit file information data. * short_fn MUST be UTF-8-encoded */ void GNUNET_FS_GTK_edit_publish_dialog (GtkWindow * parent, int do_index /* FIXME: not needed? */, const char *short_fn, const struct GNUNET_FS_BlockOptions bo, struct GNUNET_FS_FileInformation *fip, gboolean allow_no_keywords, GtkListStore *anon_liststore, GNUNET_FS_GTK_EditPublishDialogCallback cb, gpointer cb_cls) { GtkTreeIter iter; gint code; GtkComboBox *pubtypes_combo; GtkLabel *index_label; GtkLabel *root_label; struct EditPublicationDialogContext *ctx; ctx = GNUNET_malloc (sizeof (struct EditPublicationDialogContext)); ctx->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_edit_publication.glade", ctx); if (ctx->builder == NULL) { GNUNET_free (ctx); return; } ctx->pubtypes_liststore = GTK_LIST_STORE (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_publication_types_liststore")); ctx->metatypes_liststore = GTK_LIST_STORE (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_publication_metadata_types_liststore")); ctx->meta_treeview = GTK_TREE_VIEW (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_metadata_tree_view")); ctx->keywords_treeview = GTK_TREE_VIEW (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_keyword_list_tree_view")); ctx->edit_publication_window = GTK_WINDOW (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_window")); ctx->keywords_liststore = GTK_LIST_STORE (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_publication_keywords_liststore")); ctx->keyword_entry = GTK_ENTRY (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_keyword_entry")); ctx->confirm_button = GTK_WIDGET (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_confirm_button")); ctx->preview_image = GTK_IMAGE (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_metadata_preview_image")); ctx->meta_liststore = GTK_LIST_STORE (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_publication_metadata_liststore")); ctx->root_entry = GTK_ENTRY (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_root_entry")); ctx->expiration_year_spin = GTK_SPIN_BUTTON (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_expiration_year_spin_button")); ctx->priority_spin = GTK_SPIN_BUTTON (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_priority_spin_button")); ctx->replication_spin = GTK_SPIN_BUTTON (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_replication_spin_button")); ctx->index_checkbutton = GTK_TOGGLE_BUTTON (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_index_checkbutton")); ctx->anonymity_combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_anonymity_combobox")); gtk_combo_box_set_model (ctx->anonymity_combo, GTK_TREE_MODEL (anon_liststore)); ctx->anonymity_liststore = anon_liststore; GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->builder); /* indexing does not apply to directories */ gtk_widget_set_visible (GTK_WIDGET (ctx->index_checkbutton), !GNUNET_FS_file_information_is_directory (fip)); index_label = GTK_LABEL (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_index_label")); gtk_widget_set_visible (GTK_WIDGET (index_label), !GNUNET_FS_file_information_is_directory (fip)); gtk_widget_set_visible (GTK_WIDGET (ctx->root_entry), !allow_no_keywords); root_label = GTK_LABEL (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_root_label")); gtk_widget_set_visible (GTK_WIDGET (root_label), !allow_no_keywords); gtk_list_store_clear (ctx->keywords_liststore); gtk_list_store_clear (ctx->meta_liststore); if (NULL != short_fn) gtk_window_set_title (ctx->edit_publication_window, short_fn); else gtk_window_set_title (ctx->edit_publication_window, _("")); pubtypes_combo = GTK_COMBO_BOX (gtk_builder_get_object (ctx->builder, "GNUNET_GTK_edit_publication_type_combo")); if (gtk_combo_box_get_active_iter (pubtypes_combo, &iter)) { gtk_tree_model_get (GTK_TREE_MODEL (ctx->pubtypes_liststore), &iter, 0, &code, -1); change_metatypes (ctx, 0); } else gtk_combo_box_set_active (pubtypes_combo, 0); if (NULL != short_fn) ctx->short_fn = GNUNET_strdup (short_fn); ctx->bo = bo; ctx->fip = fip; ctx->preview_changed = GNUNET_NO; ctx->allow_no_keywords = allow_no_keywords; ctx->is_directory = GNUNET_FS_file_information_is_directory (fip); ctx->cb = cb; ctx->cb_cls = cb_cls; GNUNET_FS_file_information_inspect (fip, &file_information_extract, ctx); gtk_entry_set_text (ctx->keyword_entry, ""); gtk_widget_set_sensitive (ctx->confirm_button, allow_no_keywords ? TRUE : FALSE); gtk_window_set_transient_for (ctx->edit_publication_window, parent); gtk_window_present (ctx->edit_publication_window); } /* end of gnunet-fs-gtk-edit_publish_dialog.c */