/* This file is part of GNUnet (C) 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_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 }; /** * 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_malloc (sizeof (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 */ static void 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 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_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 user_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_malloc (sizeof (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)); /* connect signals; FIXME-GTK3: these could be connected with (modern) Glade */ g_signal_connect (G_OBJECT (udc->selection), "changed", G_CALLBACK (selection_changed_cb), udc); gtk_window_present (GTK_WINDOW (udc->dialog)); master_udc = udc; } /** * An unindex operation resumed. Setup the * internal context for Gtk. * * @param fs 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 */ 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_malloc (sizeof (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 undex 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_non_null (ue->emsg); GNUNET_free (ue->filename); GNUNET_free (ue); } /** * FS notified us that our undex 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 undex 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 undex 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 */