/* This file is part of GNUnet Copyright (C) 2012 GNUnet e.V. 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 3, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file src/fs/gnunet-fs-gtk_unindex.c * @author Christian Grothoff * @brief operations to display and unindex indexed files */ #include "gnunet-fs-gtk.h" #include "gnunet-fs-gtk_common.h" #include "gnunet-fs-gtk_event-handler.h" #include "gnunet-fs-gtk_unindex.h" /** * Columns in the unindex model. */ enum UNINDEX_ModelColumns { /** * A gchararray. */ UNINDEX_MC_FILENAME = 0, /** * A guint64. */ UNINDEX_MC_FILESIZE = 1, /** * A gchararray representing a color. */ UNINDEX_MC_BACKGROUND_COLOR = 2, /** * A 'struct UnindexEntry' (gpointer) */ UNINDEX_MC_UNINDEX_CONTEXT = 3, /** * A gfloat. */ UNINDEX_MC_UNINDEX_PROGRESS = 4, /** * A boolean. */ UNINDEX_MC_PROGRESS_VISIBLE = 5, /** * A gchararray. */ UNINDEX_MC_ERROR = 6, /** * A GdkPixbuf. */ UNINDEX_MC_STATUS_ICON = 7 }; /** * Overall context for the dialog. */ struct UnindexDialogContext { GtkBuilder *builder; /** * The dialog object. */ GtkWidget *dialog; /** * The unindex button. */ GtkWidget *unindex_button; /** * Main treeview object. */ GtkTreeView *treeview; /** * Selection of our treeview. */ GtkTreeSelection *selection; /** * Unindex data model. */ GtkTreeModel *model; /** * Context for initial listing of indexed files. */ struct GNUNET_FS_GetIndexedContext *gic; }; /** * Information for a specific unindex operation. */ struct UnindexEntry { /** * Kept in a DLL. */ struct UnindexEntry *next; /** * Next entry. */ struct UnindexEntry *prev; /** * Name of the file being unindexed. */ char *filename; /** * Error description, NULL if no error */ char *emsg; /** * Handle with FS. */ struct GNUNET_FS_UnindexContext *uc; /** * Row reference, NULL if the dialog is not open. */ GtkTreeRowReference *rr; /** * Size of the file. */ uint64_t filesize; /** * Percentage progress made so far. */ gint progress; }; /** * There can only be one. */ static struct UnindexDialogContext *master_udc; /** * Head of linked list. */ static struct UnindexEntry *ue_head; /** * Tail of linked list. */ static struct UnindexEntry *ue_tail; /** * User has clicked on the 'delete/unindex' button for the dialog. * Unindex the selected file. * * @param dummy the button * @param user_data the unindex context */ void GNUNET_FS_GTK_unindex_button_clicked_cb (GtkWidget *dummy, gpointer user_data) { struct UnindexDialogContext *udc = user_data; GtkTreeIter iter; char *filename; struct UnindexEntry *ue; GtkTreePath *path; guint64 filesize; /* find out if a file is selected */ if (! gtk_tree_selection_get_selected (udc->selection, NULL, &iter)) { GNUNET_break (0); return; } gtk_tree_model_get (udc->model, &iter, UNINDEX_MC_FILENAME, &filename, UNINDEX_MC_FILESIZE, &filesize, UNINDEX_MC_UNINDEX_CONTEXT, &ue, -1); if (NULL != ue) { GNUNET_break (0); g_free (filename); return; } ue = GNUNET_new (struct UnindexEntry); ue->filesize = filesize; GNUNET_CONTAINER_DLL_insert (ue_head, ue_tail, ue); ue->filename = GNUNET_strdup (filename); path = gtk_tree_model_get_path (udc->model, &iter); ue->rr = gtk_tree_row_reference_new (udc->model, path); gtk_tree_path_free (path); ue->uc = GNUNET_FS_unindex_start (GNUNET_FS_GTK_get_fs_handle (), filename, ue); gtk_list_store_set (GTK_LIST_STORE (udc->model), &iter, UNINDEX_MC_BACKGROUND_COLOR, "yellow", UNINDEX_MC_UNINDEX_CONTEXT, ue, UNINDEX_MC_UNINDEX_PROGRESS, 0, UNINDEX_MC_PROGRESS_VISIBLE, TRUE, -1); gtk_widget_set_sensitive (udc->unindex_button, FALSE); } /** * User has clicked on the 'close' button for the dialog. Close it. * * @param dummy the button * @param user_data the unindex context */ void GNUNET_FS_GTK_unindex_close_button_clicked_cb (GtkWidget *dummy, gpointer user_data) { struct UnindexDialogContext *udc = user_data; GtkTreeIter iter; struct UnindexEntry *ue; if (NULL != udc->gic) { GNUNET_FS_get_indexed_files_cancel (udc->gic); udc->gic = NULL; } if (gtk_tree_model_get_iter_first (udc->model, &iter)) do { gtk_tree_model_get (udc->model, &iter, UNINDEX_MC_UNINDEX_CONTEXT, &ue, -1); if (NULL != ue) { gtk_tree_row_reference_free (ue->rr); ue->rr = NULL; } } while (TRUE == gtk_tree_model_iter_next (udc->model, &iter)); gtk_widget_destroy (udc->dialog); g_object_unref (G_OBJECT (udc->builder)); GNUNET_free (udc); master_udc = NULL; } /** * The selection in the tree view changed; update the button sensitivity. * * @param ts the changed selection * @param user_data our unindex context */ void GNUNET_FS_GTK_unindex_treeview_selection_changed_cb (GtkTreeSelection *ts, gpointer user_data) { struct UnindexDialogContext *udc = user_data; GtkTreeIter iter; struct UnindexEntry *ue; /* find out if a file is selected */ if (gtk_tree_selection_get_selected (udc->selection, NULL, &iter)) { gtk_tree_model_get (udc->model, &iter, UNINDEX_MC_UNINDEX_CONTEXT, &ue, -1); if (NULL == ue) { /* selected file not already being unindexed, enable button! */ gtk_widget_set_sensitive (udc->unindex_button, TRUE); return; } } gtk_widget_set_sensitive (udc->unindex_button, FALSE); } /** * Type of a function called by "GNUNET_FS_get_indexed_files". * * @param cls closure * @param filename the name of the file, NULL for end of list * @param file_id hash of the contents of the indexed file * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ static int add_indexed_file (void *cls, const char *filename, const struct GNUNET_HashCode *file_id) { struct UnindexDialogContext *udc = cls; GtkTreeIter iter; uint64_t filesize; struct UnindexEntry *ue; GtkTreePath *path; if (NULL == filename) { /* end of list */ udc->gic = NULL; return GNUNET_OK; } if (GNUNET_OK != GNUNET_DISK_file_size (filename, &filesize, GNUNET_YES, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not access indexed file `%s'\n"), filename); return GNUNET_OK; } for (ue = ue_head; ue != NULL; ue = ue->next) if (0 == strcmp (ue->filename, filename)) break; if (NULL == ue) { gtk_list_store_insert_with_values (GTK_LIST_STORE (udc->model), &iter, G_MAXINT, UNINDEX_MC_FILENAME, filename, UNINDEX_MC_FILESIZE, (guint64) filesize, UNINDEX_MC_BACKGROUND_COLOR, "white", UNINDEX_MC_PROGRESS_VISIBLE, FALSE, -1); } else { if (NULL != ue->rr) { GNUNET_break (0); return GNUNET_OK; } gtk_list_store_insert_with_values (GTK_LIST_STORE (udc->model), &iter, G_MAXINT, UNINDEX_MC_FILENAME, filename, UNINDEX_MC_FILESIZE, (guint64) filesize, UNINDEX_MC_BACKGROUND_COLOR, (NULL == ue->emsg) ? "yellow" : "red", UNINDEX_MC_UNINDEX_CONTEXT, ue, UNINDEX_MC_UNINDEX_PROGRESS, ue->progress, UNINDEX_MC_PROGRESS_VISIBLE, TRUE, UNINDEX_MC_ERROR, ue->emsg, -1); path = gtk_tree_model_get_path (udc->model, &iter); ue->rr = gtk_tree_row_reference_new (udc->model, path); } return GNUNET_OK; } /** * User selected "List indexed files..." in menu. Display dialog. * * @param dummy the menu entry * @param data the main dialog builder, unused */ void GNUNET_GTK_main_menu_unindex_activate_cb (GtkWidget *dummy, gpointer data) { GtkWidget *toplevel; struct UnindexDialogContext *udc; if (NULL != master_udc) { /* window already exists, raise focus */ gtk_window_present (GTK_WINDOW (master_udc->dialog)); return; } udc = GNUNET_new (struct UnindexDialogContext); udc->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_unindex.glade", udc); if (NULL == udc->builder) { GNUNET_break (0); GNUNET_free (udc); return; } udc->dialog = GTK_WIDGET ( gtk_builder_get_object (udc->builder, "GNUNET_FS_GTK_unindex_dialog")); udc->treeview = GTK_TREE_VIEW ( gtk_builder_get_object (udc->builder, "GNUNET_FS_GTK_unindex_treeview")); udc->selection = gtk_tree_view_get_selection (udc->treeview); udc->unindex_button = GTK_WIDGET ( gtk_builder_get_object (udc->builder, "GNUNET_FS_GTK_unindex_button")); udc->model = GTK_TREE_MODEL ( gtk_builder_get_object (udc->builder, "GNUNET_FS_GTK_unindex_liststore")); udc->gic = GNUNET_FS_get_indexed_files (GNUNET_FS_GTK_get_fs_handle (), &add_indexed_file, udc); toplevel = gtk_widget_get_toplevel (dummy); if (GTK_IS_WINDOW (toplevel)) gtk_window_set_transient_for (GTK_WINDOW (udc->dialog), GTK_WINDOW (toplevel)); gtk_window_present (GTK_WINDOW (udc->dialog)); master_udc = udc; } /** * An unindex operation resumed. Setup the * internal context for Gtk. * * @param uc unindex context with the FS library * @param filename name of file being unindexed * @param filesize size of the file * @param completed how many bytes were done so far * @param emsg NULL if everything is fine, otherwise error message * @return entry for the resumed operation */ struct UnindexEntry * GNUNET_FS_GTK_unindex_handle_resume_ (struct GNUNET_FS_UnindexContext *uc, const char *filename, uint64_t filesize, uint64_t completed, const char *emsg) { struct UnindexEntry *ue; ue = GNUNET_new (struct UnindexEntry); ue->filename = GNUNET_strdup (filename); if (NULL != emsg) ue->emsg = GNUNET_strdup (emsg); ue->filesize = filesize; ue->uc = uc; ue->progress = (gint) ((100LL * completed) / filesize); GNUNET_CONTAINER_DLL_insert (ue_head, ue_tail, ue); return ue; } /** * FS notified us that our unindex operation was stopped. * * @param ue operation that stopped */ void GNUNET_FS_GTK_unindex_handle_stop_ (struct UnindexEntry *ue) { GtkTreePath *path; GtkTreeIter iter; GtkTreeModel *model; if (NULL != ue->rr) { path = gtk_tree_row_reference_get_path (ue->rr); model = gtk_tree_row_reference_get_model (ue->rr); gtk_tree_row_reference_free (ue->rr); ue->rr = NULL; GNUNET_assert (TRUE == gtk_tree_model_get_iter (model, &iter, path)); gtk_tree_path_free (path); gtk_list_store_set (GTK_LIST_STORE (model), &iter, UNINDEX_MC_UNINDEX_CONTEXT, NULL, -1); } GNUNET_CONTAINER_DLL_remove (ue_head, ue_tail, ue); GNUNET_free (ue->emsg); GNUNET_free (ue->filename); GNUNET_free (ue); } /** * FS notified us that our unindex operation had an error. * * @param ue operation that had an error * @param emsg error message */ void GNUNET_FS_GTK_unindex_handle_error_ (struct UnindexEntry *ue, const char *emsg) { GtkTreePath *path; GtkTreeIter iter; GtkTreeModel *model; ue->emsg = GNUNET_strdup (emsg); if (NULL == ue->rr) return; path = gtk_tree_row_reference_get_path (ue->rr); model = gtk_tree_row_reference_get_model (ue->rr); GNUNET_assert (TRUE == gtk_tree_model_get_iter (model, &iter, path)); gtk_tree_path_free (path); gtk_list_store_set (GTK_LIST_STORE (model), &iter, UNINDEX_MC_BACKGROUND_COLOR, "red", UNINDEX_MC_ERROR, emsg, -1); } /** * FS notified us that our unindex operation made progress * * @param ue operation that made progress * @param completed number of bytes completed now */ void GNUNET_FS_GTK_unindex_handle_progress_ (struct UnindexEntry *ue, uint64_t completed) { GtkTreePath *path; GtkTreeIter iter; GtkTreeModel *model; ue->progress = (gint) ((100LL * completed) / ue->filesize); if (NULL == ue->rr) return; path = gtk_tree_row_reference_get_path (ue->rr); model = gtk_tree_row_reference_get_model (ue->rr); GNUNET_assert (TRUE == gtk_tree_model_get_iter (model, &iter, path)); gtk_tree_path_free (path); gtk_list_store_set (GTK_LIST_STORE (model), &iter, UNINDEX_MC_UNINDEX_PROGRESS, ue->progress, -1); } /** * FS notified us that our unindex operation completed * * @param ue operation that completed */ void GNUNET_FS_GTK_unindex_handle_completed_ (struct UnindexEntry *ue) { GtkTreePath *path; GtkTreeIter iter; GtkTreeModel *model; if (NULL != ue->rr) { path = gtk_tree_row_reference_get_path (ue->rr); model = gtk_tree_row_reference_get_model (ue->rr); GNUNET_assert (TRUE == gtk_tree_model_get_iter (model, &iter, path)); gtk_tree_path_free (path); gtk_list_store_remove (GTK_LIST_STORE (model), &iter); gtk_tree_row_reference_free (ue->rr); ue->rr = NULL; } GNUNET_FS_unindex_stop (ue->uc); } /* end of gnunet-fs-gtk_unindex.c */