/* giFTui * Copyright (C) 2003 the giFTui team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "main.h" #include #include #include #include #include "io.h" #include "event.h" #include "configure.h" #include "signal.h" #include "util.h" #include "ui.h" #include "ui_icon.h" #include "ui_util.h" #include "ui_transfer_cb.h" #define TRANSFER_STATS_TIMEOUT (2000) #define TRANSFER_FILENAME_SIZE (300) #define TRANSFER_PROGRESS_SIZE (100) /**/ static gpointer parent_class = NULL; static void giftui_transfer_init (GiftuiTransfer *transfer); static void giftui_transfer_class_init (GiftuiTransferClass *class); static void giftui_transfer_dispose (GObject *object); /**/ GType giftui_transfer_get_type (void) { static GType transfer_type = 0; if (!transfer_type) { static const GTypeInfo transfer_type_info = { sizeof (GiftuiTransferClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) giftui_transfer_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GiftuiTransfer), 0, /* n_preallocs */ (GInstanceInitFunc) giftui_transfer_init, NULL }; transfer_type = g_type_register_static (GIFTUI_TYPE_CHILD, "GiftuiTransfer", &transfer_type_info, 0); } return transfer_type; } static void giftui_transfer_class_init (GiftuiTransferClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); object_class->dispose = giftui_transfer_dispose; return; } /**/ void giftui_transferchunk_free_data (GiftuiTransferChunk_t *c) { g_return_if_fail (c != NULL); if (c->str_size) g_free (c->str_size); if (c->str_user) g_free (c->str_user); if (c->str_state) g_free (c->str_state); if (c->str_url) g_free (c->str_url); if (c->str_speed) g_free (c->str_speed); return; } void giftui_transferchunk_free (GiftuiTransferChunk_t *c) { g_return_if_fail (c != NULL); giftui_transferchunk_free_data (c); g_free (c); return; } void giftui_transferfile_free_data (GiftuiTransferFile_t *f) { g_return_if_fail (f != NULL); if (f->str_file) g_free (f->str_file); if (f->str_size) g_free (f->str_size); if (f->str_user) g_free (f->str_user); if (f->str_state) g_free (f->str_state); if (f->str_hash) g_free (f->str_hash); if (f->str_url) g_free (f->str_url); return; } void giftui_transferfile_free (GiftuiTransferFile_t *f) { g_return_if_fail (f != NULL); giftui_transferfile_free_data (f); g_free (f); return; } void giftui_transferfile_download (GiftuiTransferFile_t *f) { Interface *iface; g_return_if_fail (f != NULL); g_return_if_fail (f->str_user != NULL); g_return_if_fail (f->str_url != NULL); g_return_if_fail (f->str_file != NULL); iface = interface_new ("ADDSOURCE", NULL); interface_put (iface, "user", f->str_user); if (f->str_hash) interface_put (iface, "hash", f->str_hash); INTERFACE_PUTLU (iface, "size", f->filesize); interface_put (iface, "url", f->str_url); interface_put (iface, "save", f->str_file); gift_send_interface (iface); interface_free (iface); return; } /**/ static void giftui_transfer_stat_timeout_list (GtkWidget *stat, GtkTreeModel *model) { gboolean ret; gulong speed, t_speed; gchar *str; GtkTreeIter iter; /* FINISH ME : ulong is not long enough to a total > 4GB, use * long long... */ t_speed = 0; ret = gtk_tree_model_get_iter_first (model, &iter); while (ret) { gtk_tree_model_get (model, &iter, TRANSFER_TRSPEED, &speed, -1); t_speed += speed; ret = gtk_tree_model_iter_next (model, &iter); } str = speed_str_human (t_speed); gtk_label_set_text (GTK_LABEL (stat), str); g_free (str); return; } static gboolean giftui_transfer_stat_timeout (GiftuiTransfer *tr) { GtkTreeModel *model; if (tr->stats_updated) return TRUE; model = gtk_tree_view_get_model (GTK_TREE_VIEW (tr->up_list)); giftui_transfer_stat_timeout_list (tr->up_stats, model); model = gtk_tree_view_get_model (GTK_TREE_VIEW (tr->down_list)); giftui_transfer_stat_timeout_list (tr->down_stats, model); tr->stats_updated = TRUE; return TRUE; } static void giftui_transfer_stat_timeout_stop (GiftuiTransfer *tr) { if (tr->stats_timeout) { g_source_remove (tr->stats_timeout); tr->stats_timeout = 0; } return; } static void giftui_transfer_stat_timeout_start (GiftuiTransfer *tr) { if (tr->stats_timeout) giftui_transfer_stat_timeout_stop (tr); tr->stats_timeout = g_timeout_add (TRANSFER_STATS_TIMEOUT, (GSourceFunc) giftui_transfer_stat_timeout, tr); return; } /**/ static void giftui_transfer_sources_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GiftuiTransfer *tr) { gchar *hash; GtkTreeIter parent; if (gtk_tree_model_iter_parent (model, &parent, iter)) iter = &parent; gtk_tree_model_get (model, iter, TRANSFER_HASH, &hash, -1); if (hash) { guint id; gchar *sid; id = gift_id_new (); sid = g_strdup_printf ("%u", id); giftui_event_register (EVENT_ITEM, id, tr, GIFTUI_REGISTRED_CB (giftui_transfer_locate_sources)); gift_send ("LOCATE", sid, "query", hash, NULL); g_free (sid); g_free (hash); } return; } static void giftui_transfer_browse_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GiftuiTransfer *tr) { gchar *user; GtkTreeIter parent; if (!gtk_tree_model_iter_parent (model, &parent, iter)) return; gtk_tree_model_get (model, iter, TRANSFER_FILENAME, &user, -1); if (user) { GtkWidget *w, *current; current = giftui_parent_current_child (GIFTUI_PARENT (GIFTUI_CHILD (tr)->parent)); w = giftui_browse_new (user); giftui_parent_insert_child (GIFTUI_PARENT (GIFTUI_CHILD (tr)->parent), current, w); g_free (user); } return; } static void giftui_transfer_pause_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GiftuiTransfer *tr) { guint id; gchar *str; GtkCellRendererProgressColor status; gtk_tree_model_get (model, iter, TRANSFER_ID, &id, TRANSFER_COLOR, &status, -1); if (!id || status == GTK_CELL_RENDERER_PROGRESS_CANCELED) return; str = g_strdup_printf ("%u", id); if (status == GTK_CELL_RENDERER_PROGRESS_PAUSED) gift_send ("TRANSFER", str, "action", "unpause", NULL); else if (status == GTK_CELL_RENDERER_PROGRESS_ACTIVE) gift_send ("TRANSFER", str, "action", "pause", NULL); g_free (str); return; } static gboolean giftui_transfer_cancel_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GiftuiTransfer *tr) { guint id; gchar *sid; gtk_tree_model_get (model, iter, TRANSFER_ID, &id, -1); if (!id) return TRUE; sid = g_strdup_printf ("%u", id); gift_send ("TRANSFER", sid, "action", "cancel", NULL); g_free (sid); return FALSE; } static gboolean giftui_transfer_remove_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GiftuiTransfer *tr) { guint id; gchar *sid, *url; GtkTreeIter parent; if (!gtk_tree_model_iter_parent (model, &parent, iter)) return FALSE; gtk_tree_model_get (model, &parent, TRANSFER_ID, &id, -1); gtk_tree_model_get (model, iter, TRANSFER_URL, &url, -1); sid = g_strdup_printf ("%u", id); gift_send ("DELSOURCE", sid, "url", url, NULL); g_free (sid); g_free (url); return TRUE; } static void giftui_transfer_clear_list (GtkTreeModel *model) { gboolean ret; guint id; GtkTreeIter iter; ret = gtk_tree_model_get_iter_first (model, &iter); while (ret) { gtk_tree_model_get (model, &iter, TRANSFER_ID, &id, -1); if (!id) { gtk_tree_store_remove (GTK_TREE_STORE (model), &iter); ret = gtk_tree_model_get_iter_first (model, &iter); } else ret = gtk_tree_model_iter_next (model, &iter); } return; } /**/ static void giftui_transfer_remove_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list == tr->down_list) gtk_tree_selection_selected_foreach_rm (gtk_tree_view_get_selection (GTK_TREE_VIEW (tr->current_list)), (GtkTreeSelectionForeachFunc) giftui_transfer_remove_iter, (gpointer) tr); return; } static void giftui_transfer_cancel_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list) gtk_tree_selection_selected_foreach_rm (gtk_tree_view_get_selection (GTK_TREE_VIEW (tr->current_list)), (GtkTreeSelectionForeachFunc) giftui_transfer_cancel_iter, (gpointer) tr); return; } static void giftui_transfer_sources_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list == tr->down_list) gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (tr->current_list)), (GtkTreeSelectionForeachFunc) giftui_transfer_sources_iter, (gpointer) tr); return; } static void giftui_transfer_pause_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list) gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (tr->current_list)), (GtkTreeSelectionForeachFunc) giftui_transfer_pause_iter, (gpointer) tr); return; } static void giftui_transfer_browse_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list) gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (tr->current_list)), (GtkTreeSelectionForeachFunc) giftui_transfer_browse_iter, (gpointer) tr); return; } static void giftui_transfer_clear_pressed (GiftuiTransfer *tr, guint action, GtkWidget *widget) { if (tr->current_list) giftui_transfer_clear_list (gtk_tree_view_get_model (GTK_TREE_VIEW (tr->current_list))); return; } static gboolean giftui_transfer_list_clicked (GiftuiTransfer *tr, GdkEventButton *event, GtkWidget *list) { if (event->button == 3) { if (GTK_WIDGET_VISIBLE (tr->popup)) { gtk_menu_popdown (GTK_MENU (tr->popup)); tr->current_list = NULL; } else { gtk_menu_popup (GTK_MENU (tr->popup), NULL, NULL, NULL, NULL, event->button, event->time); tr->current_list = list == tr->up_list ? tr->up_list : tr->down_list; } return TRUE; } return FALSE; } /**/ static void giftui_transfer_attach (GiftuiTransfer *tr) { giftui_transfer_stat_timeout_start (tr); return; } static void giftui_transfer_disconnect (GiftuiTransfer *tr) { GtkTreeStore *st_up, *st_down; g_return_if_fail (tr != NULL); giftui_transfer_stat_timeout_stop (tr); st_up = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tr->up_list))); st_down = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tr->down_list))); gtk_tree_store_clear (st_up); gtk_tree_store_clear (st_down); giftui_transfer_stat_timeout (tr); giftui_child_set_highlight (GIFTUI_CHILD (tr), TRUE); return; } /**/ static GtkItemFactoryEntry menu_items[] = { { "/Get sources", "", giftui_transfer_sources_pressed, 0, "", GTK_STOCK_FIND}, { "/sep1", NULL, NULL, 0, "", NULL}, { "/Remove source", "", giftui_transfer_remove_pressed, 0, "", GTK_STOCK_REMOVE}, { "/Browse user's files", "", giftui_transfer_browse_pressed, 0, "", GTK_STOCK_INDEX}, { "/sep1", NULL, NULL, 0, "", NULL}, { "/Pause-Resume", "", giftui_transfer_pause_pressed, 0, "", NULL}, { "/Cancel", "", giftui_transfer_cancel_pressed, 0, "", GTK_STOCK_DELETE}, { "/sep1", NULL, NULL, 0, "", NULL}, { "/Clear", "", giftui_transfer_clear_pressed, 0, "", GTK_STOCK_CLEAR} }; static GtkWidget * giftui_transfer_create_list (GtkWidget **treeview, GtkWidget **stat) { GType columns[] = { G_TYPE_STRING, /* filename */ G_TYPE_FLOAT, /* progress */ G_TYPE_STRING, /* size, human readable */ G_TYPE_STRING, /* speed */ G_TYPE_STRING, /* state */ G_TYPE_STRING, /* url */ G_TYPE_STRING, /* hash */ G_TYPE_FLOAT, /* start */ G_TYPE_ULONG, /* transmit */ G_TYPE_ULONG, /* size */ G_TYPE_ULONG, /* speed */ G_TYPE_STRING, /* icon */ G_TYPE_UINT, /* id */ G_TYPE_UINT /* color */ }; gint i; gchar *column_headers[] = { _("Filename/User"), _("Progress"), _("Size"), _("Speed"), _("State") }; GtkWidget *box, *scrolled; GtkTreeStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; box = gtk_vbox_new (FALSE, 0); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 5); store = gtk_tree_store_newv (TRANSFER_NUMBER, columns); *treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); gtk_container_add (GTK_CONTAINER (scrolled), *treeview); /* refcount is 2 (1 for store variable, and 1 into the * gtktreeview widget). */ g_object_unref (G_OBJECT (store)); /* create columns */ for (i = 0 ; i <= TRANSFER_STATE ; i++) { column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, column_headers[i]); switch (i) { case TRANSFER_FILENAME: renderer = gtk_cell_renderer_pixbuf_new (); g_object_set (renderer, "stock_size", GTK_ICON_SIZE_MENU, NULL); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "stock_id", TRANSFER_ICON, NULL); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "text", i, NULL); break; case TRANSFER_PROGRESS: renderer = gtk_cell_renderer_progress_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, "value", i, "value_start", TRANSFER_START, "progressground", TRANSFER_COLOR, NULL); break; default: renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_column_set_attributes (column, renderer, "text", i, NULL); break; } switch (i) { case TRANSFER_SIZE: gtk_tree_view_column_set_sort_column_id (column, TRANSFER_FILESIZE); break; case TRANSFER_SPEED: gtk_tree_view_column_set_sort_column_id (column, TRANSFER_TRSPEED); break; default: if (i == TRANSFER_FILENAME) { gtk_tree_view_column_set_fixed_width (column, TRANSFER_FILENAME_SIZE); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); } else if (i == TRANSFER_PROGRESS) { gtk_tree_view_column_set_fixed_width (column, TRANSFER_PROGRESS_SIZE); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); } else { gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); } gtk_tree_view_column_set_sort_column_id (column, i); break; } gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (*treeview), column); } *stat = gtk_label_new (NULL); gtk_label_set_justify (GTK_LABEL (*stat), GTK_JUSTIFY_RIGHT); gtk_box_pack_start (GTK_BOX (box), *stat, FALSE, FALSE, 0); return box; } static void giftui_transfer_init (GiftuiTransfer *transfer) { GtkWidget *vbox; GtkWidget *results_frame; GtkTreeSelection *select; GiftuiChild *child; child = GIFTUI_CHILD (transfer); vbox = GTK_WIDGET (transfer); child->type = GIFTUI_CHILD_TRANSFER; g_object_set (G_OBJECT (transfer), "label", _("Transfers"), "stock", GTK_STOCK_REFRESH, NULL); /* popup */ transfer->popup = gtk_menu_from_factoryentry (menu_items, GTK_TYPE_MENU, sizeof (menu_items) / sizeof (menu_items[0]), NULL, transfer); gtk_widget_hide (transfer->popup); /**/ transfer->paned = gtk_vpaned_new (); gtk_box_pack_start_defaults (GTK_BOX (vbox), transfer->paned); /**/ results_frame = gtk_frame_new (_("Downloads")); gtk_container_set_border_width (GTK_CONTAINER (results_frame), 5); gtk_frame_set_shadow_type (GTK_FRAME (results_frame), GTK_SHADOW_NONE); gtk_paned_add1 (GTK_PANED (transfer->paned), results_frame); gtk_container_add (GTK_CONTAINER (results_frame), giftui_transfer_create_list (&transfer->down_list, &transfer->down_stats)); select = gtk_tree_view_get_selection (GTK_TREE_VIEW (transfer->down_list)); gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); g_signal_connect_swapped (transfer->down_list, "button-press-event", G_CALLBACK (giftui_transfer_list_clicked), transfer); /**/ results_frame = gtk_frame_new (_("Uploads")); gtk_container_set_border_width (GTK_CONTAINER (results_frame), 5); gtk_frame_set_shadow_type (GTK_FRAME (results_frame), GTK_SHADOW_NONE); gtk_paned_add2 (GTK_PANED (transfer->paned), results_frame); gtk_container_add (GTK_CONTAINER (results_frame), giftui_transfer_create_list (&transfer->up_list, &transfer->up_stats)); select = gtk_tree_view_get_selection (GTK_TREE_VIEW (transfer->up_list)); gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); g_signal_connect_swapped (transfer->up_list, "button-press-event", G_CALLBACK (giftui_transfer_list_clicked), transfer); return; } GtkWidget * giftui_transfer_new (void) { GiftuiTransfer *transfer; transfer = g_object_new (GIFTUI_TYPE_TRANSFER, "close", FALSE, NULL); gtk_paned_set_position (GTK_PANED (transfer->paned), giftui_config_get_int (PREFS_TRANSFERS_PANED_HEIGHT)); giftui_transfer_update_colors (transfer); /* Registration for downloads. */ giftui_event_register (EVENT_ADDDOWNLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_add)); giftui_event_register (EVENT_CHGDOWNLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_update)); giftui_event_register (EVENT_DELDOWNLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_del)); giftui_event_register (EVENT_ADDSOURCE, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_add)); giftui_event_register (EVENT_DELSOURCE, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_del)); /* Registration for uploads. */ giftui_event_register (EVENT_ADDUPLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_add)); giftui_event_register (EVENT_CHGUPLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_update)); giftui_event_register (EVENT_DELUPLOAD, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_updownload_del)); /* Disconnect & close */ giftui_event_register (EVENT_DISCONNECT, 0, transfer, GIFTUI_REGISTRED_CB( giftui_transfer_disconnect)); giftui_event_register (EVENT_CLOSE, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_disconnect)); /* Start stats */ giftui_event_register (EVENT_ATTACH, 0, transfer, GIFTUI_REGISTRED_CB (giftui_transfer_attach)); /* datas */ giftui_signal_register (PREFS_TRANSFERS_ACTIVE_COLOR, GIFTUI_HANDLER_CB (giftui_transfer_update_colors), transfer); giftui_signal_register (PREFS_TRANSFERS_COMPLETED_COLOR, GIFTUI_HANDLER_CB (giftui_transfer_update_colors), transfer); giftui_signal_register (PREFS_TRANSFERS_PAUSED_COLOR, GIFTUI_HANDLER_CB (giftui_transfer_update_colors), transfer); giftui_signal_register (PREFS_TRANSFERS_CANCELED_COLOR, GIFTUI_HANDLER_CB (giftui_transfer_update_colors), transfer); gtk_widget_show_all (GTK_WIDGET (transfer)); return GTK_WIDGET (transfer); } static void giftui_transfer_dispose (GObject *object) { GiftuiTransfer *tr = GIFTUI_TRANSFER (object); giftui_config_set_int (PREFS_TRANSFERS_PANED_HEIGHT, gtk_paned_get_position (GTK_PANED (tr->paned))); giftui_transfer_stat_timeout_stop (tr); giftui_event_unregister_all (tr); if (tr->popup) { gtk_widget_destroy (tr->popup); tr->popup = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); return; }