/* 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 #include #include "io.h" #include "event.h" #include "util.h" #include "ui.h" #include "ui_icon.h" #include "ui_util.h" #define BROWSE_FILENAME_SIZE (500) /**/ typedef enum { /* Displayed */ BROWSE_FILENAME = 0, BROWSE_SIZE, /* Hided */ BROWSE_ICON, BROWSE_URL, BROWSE_HASH, BROWSE_FILESIZE, BROWSE_NUMBER } GiftuiBrowseColumn_t; static gpointer parent_class = NULL; static void giftui_browse_init (GiftuiBrowse *browse); static void giftui_browse_class_init (GiftuiBrowseClass *class); static void giftui_browse_dispose (GObject *object); /**/ GType giftui_browse_get_type (void) { static GType browse_type = 0; if (!browse_type) { static const GTypeInfo browse_type_info = { sizeof (GiftuiBrowseClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) giftui_browse_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GiftuiBrowse), 0, /* n_preallocs */ (GInstanceInitFunc) giftui_browse_init, NULL }; browse_type = g_type_register_static (GIFTUI_TYPE_CHILD, "GiftuiBrowse", &browse_type_info, 0); } return browse_type; } static void giftui_browse_class_init (GiftuiBrowseClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); object_class->dispose = giftui_browse_dispose; return; } /**/ static void giftui_browse_set_name_from_host (GiftuiBrowse *browse, const gchar *host) { gchar *s, *user; if (host) { user = g_strdup (host); if ((s = strchr (user, '@'))) *s = '\0'; g_object_set (G_OBJECT (browse), "label", user, NULL); g_free (user); } else giftui_child_set_text (GIFTUI_CHILD (browse), NULL); return; } static gboolean __check_if_exist (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, const gchar *dir) { gboolean ret; gchar *stored_dir; ret = gtk_tree_model_iter_children (model, iter, parent); while (ret) { gtk_tree_model_get (model, iter, BROWSE_FILENAME, &stored_dir, -1); if (stored_dir && !strcmp (stored_dir, dir)) { g_free (stored_dir); return TRUE; } g_free (stored_dir); ret = gtk_tree_model_iter_next (model, iter); } return FALSE; } static void giftui_browse_add_directorys (GtkTreeModel *model, GtkTreeIter **parent, gchar **path) { gchar *s1, *s2; GtkTreeIter *p, *child, *tmp; child = g_new0 (GtkTreeIter, 1); /* Find the good directory where we put this file, and create * it if it doesn't exist. */ s1 = *path + 1; p = *parent; while ((s2 = strchr (s1, '/'))) { *s2 = '\0'; if (!__check_if_exist (model, child, p, s1)) { gtk_tree_store_append (GTK_TREE_STORE (model), child, p); gtk_tree_store_set (GTK_TREE_STORE (model), child, BROWSE_FILENAME, s1, BROWSE_ICON, GTK_STOCK_OPEN, -1); } tmp = p; p = child; child = tmp; s1 = s2 + 1; } gtk_tree_iter_free (child); *parent = p; *path = s1; return; } static void giftui_browse_add_result (GiftuiBrowse *br, GiftuiEvent_t *in) { /* Displayed strings & variables */ gulong filesize; gchar *path, *filename, *size; /* Others */ gchar *hash, *url, *icon, *network; GtkTreeIter *parent, child; GtkTreeModel *model; g_return_if_fail (br != NULL); g_return_if_fail (in != NULL); if ((filename = g_strdup (interface_get (in->iface, "file"))) == NULL) { widget_set_sensitivity_invert (br->stop); widget_set_sensitivity_invert (br->refresh); giftui_event_unregister_all ((gpointer) br); br->id = 0; return; } parent = g_new0 (GtkTreeIter, 1); model = gtk_tree_view_get_model (GTK_TREE_VIEW (br->list)); if (!gtk_tree_model_get_iter_first (model, parent)) { gtk_tree_store_append (GTK_TREE_STORE (model), parent, NULL); gtk_tree_store_set (GTK_TREE_STORE (model), parent, BROWSE_FILENAME, br->user, BROWSE_ICON, GTK_STOCK_INDEX, -1); } path = filename; giftui_browse_add_directorys (model, &parent, &path); if (!__check_if_exist (model, &child, parent, path)) { url = interface_get (in->iface, "url"); hash = interface_get (in->iface, "hash"); filesize = INTERFACE_GETLU (in->iface, "size"); size = size_str_human (filesize); if (gtk_image_get_storage_type (GTK_IMAGE (br->icon)) == GTK_IMAGE_EMPTY) { if ((network = network_name_from_url (url))) { if ((icon = giftui_icon_stock (ICON_NETWORK, network))) { gtk_image_set_from_stock (GTK_IMAGE (br->icon), icon, GTK_ICON_SIZE_BUTTON); g_free (icon); } g_free (network); } } gtk_tree_store_append (GTK_TREE_STORE (model), &child, parent); gtk_tree_store_set (GTK_TREE_STORE (model), &child, BROWSE_FILENAME, path, BROWSE_SIZE, size, BROWSE_URL, url, BROWSE_HASH, hash, BROWSE_FILESIZE, filesize, BROWSE_ICON, GTK_STOCK_NEW, -1); network = g_strdup_printf (_("%u files"), br->files++); gtk_label_set_text (GTK_LABEL (br->stats), network); giftui_child_set_highlight (GIFTUI_CHILD (br), TRUE); g_free (network); g_free (size); } gtk_tree_iter_free (parent); g_free (filename); return; } /**/ static void giftui_browse_stats_reset (GiftuiBrowse *br) { gchar *str; g_return_if_fail (br != NULL); br->files = 0; str = g_strdup_printf (_("%u files"), br->files); gtk_label_set_text (GTK_LABEL (br->stats), str); g_free (str); return; } static void giftui_browse_stop_browse (GiftuiBrowse *br) { gchar *id; g_return_if_fail (br != NULL); if (!br->id) return; id = g_strdup_printf ("%u", br->id); gift_send ("BROWSE", id, "action", "cancel", NULL); g_free (id); giftui_event_unregister (br, EVENT_ITEM, br->id); /* Update UI */ widget_set_sensitivity_invert (br->stop); widget_set_sensitivity_invert (br->refresh); br->id = 0; return; } static void giftui_browse_start_browse (GiftuiBrowse *br) { const gchar *uuser; gchar tmp[10]; GtkTreeStore *tree; Interface *iface; g_return_if_fail (br != NULL); /* Stop the old browse. */ if (br->id) giftui_browse_stop_browse (br); /* Clear the Tree. */ tree = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (br->list))); gtk_tree_store_clear (tree); uuser = gtk_entry_get_text (GTK_ENTRY (br->entry)); if (!uuser || (*uuser == '\0')) return; if (br->user != NULL) g_free (br->user); br->user = str_convert_to_ascii (uuser); if (!gift_connected () || strlen (br->user) < 1) return; br->id = gift_id_new (); snprintf (tmp, 9, "%u", br->id); iface = interface_new ("BROWSE", tmp); interface_put (iface, "query", br->user); /* Registration for the new browse. */ giftui_event_register (EVENT_ITEM, br->id, br, GIFTUI_REGISTRED_CB (giftui_browse_add_result)); /* We send the command. */ gift_send_interface (iface); giftui_browse_stats_reset (br); /* Update UI */ widget_set_sensitivity_invert (br->stop); widget_set_sensitivity_invert (br->refresh); giftui_browse_set_name_from_host (br, br->user); interface_free (iface); return; } /**/ static void giftui_browse_download_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *selected, GiftuiBrowse *br) { GiftuiTransferFile_t file; memset (&file, 0, sizeof (GiftuiTransferFile_t)); gtk_tree_model_get (model, selected, BROWSE_HASH, &file.str_hash, BROWSE_URL, &file.str_url, BROWSE_FILENAME, &file.str_file, BROWSE_FILESIZE, &file.filesize, -1); if (file.str_url) { file.str_user = g_strdup (br->user); giftui_transferfile_download (&file); } giftui_transferfile_free_data (&file); return; } /**/ static void giftui_browse_download_pressed (GiftuiBrowse *br, guint action, GtkWidget *widget) { gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (br->list)), (GtkTreeSelectionForeachFunc) giftui_browse_download_iter, br); return; } static void giftui_browse_list_actived (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GiftuiBrowse *br) { GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model (treeview); if (gtk_tree_model_get_iter (model, &iter, path)) giftui_browse_download_iter (model, path, &iter, br); return; } static gboolean giftui_browse_list_clicked (GiftuiBrowse *br, GdkEventButton *event) { if (event->button == 3) { if (GTK_WIDGET_VISIBLE (br->popup)) gtk_menu_popdown (GTK_MENU (br->popup)); else gtk_menu_popup (GTK_MENU (br->popup), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } return FALSE; } static gboolean giftui_browse_entry_pressed (GtkWidget *entry, GdkEventKey *event, GiftuiBrowse *br) { if (event->keyval == GDK_Return) giftui_browse_start_browse (br); return FALSE; } static GtkItemFactoryEntry menu_items[] = { { "/Download", "", giftui_browse_download_pressed, 0, "", GTK_STOCK_SAVE} }; static void giftui_browse_init (GiftuiBrowse *browse) { gint i; gchar *column_header[] = { "Filename", "Size" }; GtkWidget *vbox, *hbox, *label; GtkWidget *results_frame, *scrolled; GtkTreeSelection *select; GtkTreeStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GiftuiChild *child; child = GIFTUI_CHILD (browse); vbox = GTK_WIDGET (browse); browse->id = 0; child->type = GIFTUI_CHILD_BROWSE; g_object_set (G_OBJECT (browse), "stock", GTK_STOCK_INDEX, NULL); /* Popup */ browse->popup = gtk_menu_from_factoryentry (menu_items, GTK_TYPE_MENU, sizeof (menu_items) / sizeof (menu_items[0]), NULL, child); gtk_widget_hide (browse->popup); /* "Query" label */ hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5); label = gtk_label_new (_("User")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 5); /* entry for search string */ browse->entry = gtk_entry_new (); gtk_entry_set_max_length (GTK_ENTRY (browse->entry), 256); gtk_entry_select_region (GTK_ENTRY (browse->entry), 0, 0); gtk_box_pack_start (GTK_BOX (hbox), browse->entry, TRUE, TRUE, 5); g_signal_connect (browse->entry, "key-press-event", G_CALLBACK (giftui_browse_entry_pressed), browse); browse->icon = gtk_image_new (); gtk_box_pack_start (GTK_BOX (hbox), browse->icon, TRUE, TRUE, 5); browse->stats = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (hbox), browse->stats, TRUE, TRUE, 5); /* search button */ browse->refresh = gtk_button_new_from_stock ("gtk-refresh"); g_signal_connect_swapped (browse->refresh, "clicked", G_CALLBACK (giftui_browse_start_browse), browse); gtk_box_pack_start (GTK_BOX (hbox), browse->refresh, FALSE, FALSE, 5); /* stop button */ browse->stop = gtk_button_new_from_stock ("gtk-stop"); g_signal_connect_swapped (browse->stop, "clicked", G_CALLBACK (giftui_browse_stop_browse), (gpointer) browse); gtk_box_pack_start (GTK_BOX (hbox), browse->stop, FALSE, FALSE, 5); widget_set_sensitivity_invert (browse->stop); /* search results frame */ results_frame = gtk_frame_new (_("List")); gtk_container_set_border_width (GTK_CONTAINER (results_frame), 5); gtk_frame_set_shadow_type (GTK_FRAME (results_frame), GTK_SHADOW_NONE); gtk_box_pack_start (GTK_BOX (vbox), results_frame, TRUE, TRUE, 5); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (results_frame), scrolled); store = gtk_tree_store_new (BROWSE_NUMBER, G_TYPE_STRING, /* filename */ G_TYPE_STRING, /* size, human readable */ G_TYPE_STRING, /* icon */ G_TYPE_STRING, /* url */ G_TYPE_STRING, /* hash */ G_TYPE_ULONG /* size */ ); browse->list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); /* refcount is 2 (1 for store variable, and 1 into the * gtktreeview widget). */ g_object_unref (G_OBJECT (store)); gtk_container_add (GTK_CONTAINER (scrolled), browse->list); /* create columns */ for (i = 0 ; i <= BROWSE_SIZE ; i++) { switch (i) { case BROWSE_FILENAME: column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, column_header[i]); 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", BROWSE_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", BROWSE_FILENAME, NULL); gtk_tree_view_column_set_fixed_width (column, BROWSE_FILENAME_SIZE); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_sort_column_id (column, i); break; case BROWSE_SIZE: renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (column_header[i], renderer, "text", i, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_column_set_sort_column_id (column, BROWSE_FILESIZE); break; default: column = NULL; } gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (browse->list), column); } select = gtk_tree_view_get_selection (GTK_TREE_VIEW (browse->list)); gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); g_signal_connect_swapped (browse->list, "button-press-event", G_CALLBACK (giftui_browse_list_clicked), browse); g_signal_connect (browse->list, "row-activated", G_CALLBACK (giftui_browse_list_actived), browse); return; } /**/ static void giftui_browse_disconnect (GiftuiBrowse *br) { GtkTreeStore *st; g_return_if_fail (br != NULL); giftui_browse_stop_browse (br); st = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (br->list))); gtk_tree_store_clear (st); return; } GtkWidget * giftui_browse_new (const gchar *user) { GiftuiBrowse *browse; browse = g_object_new (GIFTUI_TYPE_BROWSE, NULL); giftui_event_register (EVENT_DISCONNECT, 0, browse, GIFTUI_REGISTRED_CB (giftui_browse_disconnect)); giftui_event_register (EVENT_CLOSE, 0, browse, GIFTUI_REGISTRED_CB (giftui_browse_disconnect)); if (user) { browse->user = g_strdup (user); gtk_entry_set_text (GTK_ENTRY (browse->entry), user); giftui_browse_set_name_from_host (browse, user); giftui_browse_start_browse (browse); } else giftui_child_set_text (GIFTUI_CHILD (browse), _("Browse")); gtk_widget_show_all (GTK_WIDGET (browse)); return GTK_WIDGET (browse); } static void giftui_browse_dispose (GObject *object) { GiftuiBrowse *br = GIFTUI_BROWSE (object); giftui_event_unregister_all (br); giftui_browse_stop_browse (br); if (br->popup != NULL) gtk_widget_destroy (br->popup); G_OBJECT_CLASS (parent_class)->dispose (object); return; }