/* 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 "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_search_cb.h" #define SEARCH_FILENAME_SIZE (400) #define SEARCH_ENTRY_MAX (256) /**/ static gpointer parent_class = NULL; static void giftui_search_init (GiftuiSearch *search); static void giftui_search_class_init (GiftuiSearchClass *class); static void giftui_search_dispose (GObject *object); /**/ GType giftui_search_get_type (void) { static GType search_type = 0; if (!search_type) { static const GTypeInfo search_type_info = { sizeof (GiftuiSearchClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) giftui_search_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GiftuiSearch), 0, /* n_preallocs */ (GInstanceInitFunc) giftui_search_init, NULL }; search_type = g_type_register_static (GIFTUI_TYPE_CHILD, "GiftuiSearch", &search_type_info, 0); } return search_type; } static void giftui_search_class_init (GiftuiSearchClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); object_class->dispose = giftui_search_dispose; return; } /**/ static gchar *search_type[] = { "everything", "audio", "video", "image", "text", "document", "software" , NULL }; static void giftui_search_start_search_display (GiftuiSearch *se, guint id, const gchar *include, const gchar *exclude) { gchar search_text[512]; GtkTreeStore *tree; GtkTreeIter iter; snprintf (search_text, 511, _("%s / Running..."), include); tree = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (se->list))); gtk_tree_store_append (tree, &iter, NULL); gtk_menu_get_title (GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (se->type)))); gtk_tree_store_set (tree, &iter, SEARCH_FILENAME, search_text, SEARCH_SOURCES, 0, SEARCH_ID, id, SEARCH_ICON, GTK_STOCK_FIND, -1); gtk_combo_entry_add_text (GTK_COMBO (se->combo_include), include); if (exclude && (*exclude != '\0')) gtk_combo_entry_add_text (GTK_COMBO (se->combo_exclude), exclude); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (se->combo_include)->entry), ""); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (se->combo_exclude)->entry), ""); return; } static void giftui_search_start_search (GiftuiSearch *se) { guint id, sel; const gchar *utext_include, *utext_exclude; gchar *atext_include, *atext_exclude, *sid, *type, *network; Interface *iface; if (!gift_connected ()) return; /* Welcome to giFT, can I take your order please ? */ utext_include = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (se->combo_include)->entry)); utext_exclude = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (se->combo_exclude)->entry)); if ((utext_include == NULL) || (*utext_include == '\0')) return; atext_include = str_convert_to_ascii (utext_include); if ((utext_exclude != NULL) && (*utext_exclude != '\0')) atext_exclude = str_convert_to_ascii (utext_exclude); else atext_exclude = NULL; se->running++; /* id */ id = gift_id_new (); sid = g_strdup_printf ("%i", id); iface = interface_new ("SEARCH", sid); g_free (sid); /* include */ interface_put (iface, "query", atext_include); /* exclude */ if (atext_exclude) interface_put (iface, "exclude", atext_exclude); /* type */ if ((sel = gtk_option_menu_get_history (GTK_OPTION_MENU (se->type)))) { type = search_type[sel]; interface_put (iface, "realm", type); } /* network */ if ((sel = gtk_option_menu_get_history (GTK_OPTION_MENU (se->network))) > 0) { network = network_list_get_index ((GArray *) giftui_data_get (PREFS_SEARCH_NETWORKS), sel - 1); if (network) interface_put (iface, "protocol", network); } else network = NULL; /* Add the search to the tree. */ giftui_search_start_search_display (se, id, utext_include, utext_exclude); /* Registration for the new search. */ giftui_event_register (EVENT_ITEM, id, se, GIFTUI_REGISTRED_CB (giftui_search_add_result)); /* We send everything to giFT. */ gift_send_interface (iface); g_free (atext_include); if (atext_exclude) g_free (atext_exclude); interface_free (iface); return; } static void giftui_search_download_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *selected, GiftuiSearch *se) { gboolean download, ret; GtkTreeIter parent; GiftuiTransferFile_t file; /* No parent, so it's not a result. */ if (!gtk_tree_model_iter_parent (model, &parent, selected)) return; memset (&file, 0, sizeof (GiftuiTransferFile_t)); if (gtk_tree_model_iter_has_child (model, selected)) { GtkTreeIter iter; gtk_tree_model_get (model, selected, SEARCH_FILESIZE, &file.filesize, SEARCH_HASH, &file.str_hash, SEARCH_FILENAME, &file.str_file, -1); /* get all sources */ ret = gtk_tree_model_iter_children (model, &iter, selected); while (ret) { gtk_tree_model_get (model, &iter, SEARCH_ISDOWNLOAD, &download, -1); if (!download) { gtk_tree_model_get (model, &iter, SEARCH_FILENAME, &file.str_user, SEARCH_URL, &file.str_url, -1); gtk_tree_store_set (GTK_TREE_STORE (model), &iter, SEARCH_ISDOWNLOAD, TRUE, -1); giftui_transferfile_download (&file); g_free (file.str_url); g_free (file.str_user); } ret = gtk_tree_model_iter_next (model, &iter); } if (file.str_hash) g_free (file.str_hash); g_free (file.str_file); } else { /* get only one. */ gtk_tree_model_get (model, selected, SEARCH_ISDOWNLOAD, &download, -1); if (!download) { gtk_tree_model_get (model, &parent, SEARCH_FILESIZE, &file.filesize, SEARCH_HASH, &file.str_hash, SEARCH_FILENAME, &file.str_file, -1); gtk_tree_model_get (model, selected, SEARCH_FILENAME, &file.str_user, SEARCH_URL, &file.str_url, -1); gtk_tree_store_set (GTK_TREE_STORE (model), selected, SEARCH_ISDOWNLOAD, TRUE, -1); giftui_transferfile_download (&file); giftui_transferfile_free_data (&file); } } return; } static void giftui_search_browse_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *selected, GiftuiSearch *se) { gchar *user; GtkTreeIter iter; if (!gtk_tree_model_iter_parent (model, &iter, selected) || gtk_tree_model_iter_has_child (model, selected)) return; gtk_tree_model_get (model, selected, SEARCH_FILENAME, &user, -1); if (user) { GtkWidget *w, *current; current = giftui_parent_current_child (GIFTUI_PARENT (GIFTUI_CHILD (se)->parent)); w = giftui_browse_new (user); giftui_parent_insert_child (GIFTUI_PARENT (GIFTUI_CHILD (se)->parent), current, w); g_free (user); } return; } static gboolean giftui_search_stop_search_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *selected, GiftuiSearch *se) { gint id; gchar *tmp, str[1024]; GtkTreeIter master; /* Not a search node. */ if (gtk_tree_model_iter_parent (model, &master, selected)) return FALSE; /* Already stopped ? */ gtk_tree_model_get (model, selected, SEARCH_ID, &id, -1); if (!id) return TRUE; se->running--; sprintf (str, "%u", id); if (gift_connected ()) gift_send ("SEARCH", str, "action", "cancel", NULL); giftui_event_unregister (se, EVENT_ITEM, id); gtk_tree_model_get (model, selected, SEARCH_FILENAME, &tmp, -1); strcpy (str, tmp); g_free (tmp); if ((tmp = strrchr (str, '/'))) { *tmp = '\0'; strncat (str, _("/ Stopped"), 1023); } gtk_tree_store_set (GTK_TREE_STORE (model), selected, SEARCH_FILENAME, str, SEARCH_ID, 0, -1); return TRUE; } static void giftui_search_stop_all (GiftuiSearch *se) { gboolean ret; GtkTreeModel *model; GtkTreeIter iter; g_return_if_fail (se != NULL); model = gtk_tree_view_get_model (GTK_TREE_VIEW (se->list)); ret = gtk_tree_model_get_iter_first (model, &iter); while (ret) { giftui_search_stop_search_iter (model, NULL, &iter, se); ret = gtk_tree_model_iter_next (model, &iter); } giftui_child_set_highlight (GIFTUI_CHILD (se), TRUE); return; } static void giftui_search_remove_iter (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *selected, GiftuiSearch *se) { if (giftui_search_stop_search_iter (model, path, selected, se)) gtk_tree_store_remove (GTK_TREE_STORE (model), selected); return; } /**/ static void giftui_search_remove_pressed (GiftuiSearch *se, guint action, GtkWidget *widget) { gtk_tree_selection_selected_foreach_rm (gtk_tree_view_get_selection (GTK_TREE_VIEW (se->list)), (GtkTreeSelectionForeachFunc) giftui_search_remove_iter, (gpointer) se); return; } static void giftui_search_stop_pressed (GiftuiSearch *se, guint action, GtkWidget *widget) { gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (se->list)), (GtkTreeSelectionForeachFunc) giftui_search_stop_search_iter, (gpointer) se); return; } static void giftui_search_download_pressed (GiftuiSearch *se, guint action, GtkWidget *widget) { gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (se->list)), (GtkTreeSelectionForeachFunc) giftui_search_download_iter, (gpointer) se); return; } static void giftui_search_browse_pressed (GiftuiSearch *se, guint action, GtkWidget *widget) { gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (GTK_TREE_VIEW (se->list)), (GtkTreeSelectionForeachFunc) giftui_search_browse_iter, (gpointer) se); return; } static void giftui_search_list_actived (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GiftuiSearch *se) { GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model (treeview); if (gtk_tree_model_get_iter (model, &iter, path)) giftui_search_download_iter (model, path, &iter, se); return; } static gboolean giftui_search_list_clicked (GiftuiSearch *se, GdkEventButton *event) { if (event->button == 3) { if (GTK_WIDGET_VISIBLE (se->popup)) gtk_menu_popdown (GTK_MENU (se->popup)); else gtk_menu_popup (GTK_MENU (se->popup), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } return FALSE; } static gboolean giftui_search_entry_pressed (GtkWidget *entry, GdkEventKey *event, GiftuiSearch *se) { if (event->keyval == GDK_Return) giftui_search_start_search (se); return FALSE; } /**/ static void giftui_search_init (GiftuiSearch *search) { gint i; gchar *column_headers[] = { _("Query/Filename"), _("Avail."), _("Sources"), _("Size") }; GtkWidget *hbox, *vbox; GtkWidget *button; GtkWidget *menu; GtkWidget *results_frame, *scrolled; GtkTreeSelection *select; GtkTreeStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GiftuiChild *child; static GtkItemFactoryEntry menu_items[] = { { "/Stop", "", giftui_search_stop_pressed, 0, "", GTK_STOCK_STOP}, { "/Remove", "", giftui_search_remove_pressed, 0, "", GTK_STOCK_DELETE}, { "/sep1", NULL, NULL, 0, "", NULL}, { "/Download", "", giftui_search_download_pressed, 0, "", GTK_STOCK_SAVE}, { "/Browse user's files", "", giftui_search_browse_pressed, 0, "", GTK_STOCK_INDEX} }; child = GIFTUI_CHILD (search); vbox = GTK_WIDGET (search); child->type = GIFTUI_CHILD_SEARCH; g_object_set (G_OBJECT (search), "label", _("Search"), "stock", GTK_STOCK_FIND, NULL); /* popup */ search->popup = gtk_menu_from_factoryentry (menu_items, GTK_TYPE_MENU, sizeof (menu_items) / sizeof (menu_items[0]), NULL, search); gtk_widget_hide (search->popup); /* "Query" label */ hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5); search->combo_include = gtk_combo_add_with_title (GTK_BOX (hbox), _("Query"), SEARCH_ENTRY_MAX); g_signal_connect (GTK_COMBO (search->combo_include)->entry, "key-press-event", G_CALLBACK (giftui_search_entry_pressed), search); search->combo_exclude = gtk_combo_add_with_title (GTK_BOX (hbox), _("Exclude"), SEARCH_ENTRY_MAX); g_signal_connect (GTK_COMBO (search->combo_exclude)->entry, "key-press-event", G_CALLBACK (giftui_search_entry_pressed), search); /* Type */ hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5); search->type = gtk_option_menu_new (); menu = widget_menu_add (NULL); widget_menu_item_add (GTK_MENU (menu), _("all files")); widget_menu_item_add (GTK_MENU (menu), _("audio")); widget_menu_item_add (GTK_MENU (menu), _("video")); widget_menu_item_add (GTK_MENU (menu), _("picture")); widget_menu_item_add (GTK_MENU (menu), _("text")); widget_menu_item_add (GTK_MENU (menu), _("document")); widget_menu_item_add (GTK_MENU (menu), _("software")); gtk_option_menu_set_menu (GTK_OPTION_MENU (search->type), menu); gtk_option_menu_set_history (GTK_OPTION_MENU (search->type), SEARCH_ALL); gtk_box_pack_start (GTK_BOX (hbox), search->type, FALSE, FALSE, 5); /* Network */ search->network = gtk_option_menu_new (); giftui_search_update_networks (search); gtk_box_pack_start (GTK_BOX (hbox), search->network, FALSE, FALSE, 5); /* search button */ button = gtk_button_new_from_stock ("gtk-find"); g_signal_connect_swapped (button, "clicked", G_CALLBACK (giftui_search_start_search), search); gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 5); /* search results frame */ results_frame = gtk_frame_new (_("Results")); 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 (SEARCH_NUMBER, G_TYPE_STRING, /* filename */ G_TYPE_BOOLEAN, /* available? */ G_TYPE_UINT, /* number of sources */ G_TYPE_STRING, /* size, human readable */ G_TYPE_STRING, /* url */ G_TYPE_STRING, /* hash */ G_TYPE_ULONG, /* size */ G_TYPE_STRING, /* icon */ G_TYPE_BOOLEAN, /* Download has * been started */ G_TYPE_UINT, /* Id */ GDK_TYPE_PIXBUF ); search->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 (store); gtk_container_add (GTK_CONTAINER (scrolled), search->list); /* create columns */ for (i = 0 ; i <= SEARCH_SIZE ; i++) { switch (i) { case SEARCH_FILENAME: column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, column_headers[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", SEARCH_ICON, "pixbuf", SEARCH_PIXBUF, 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", SEARCH_FILENAME, NULL); gtk_tree_view_column_set_fixed_width (column, SEARCH_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 SEARCH_SIZE: renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (column_headers[i], renderer, "text", i, NULL); gtk_tree_view_column_set_sort_column_id (column, SEARCH_FILESIZE); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); break; case SEARCH_AVAILABILITY: renderer = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes (column_headers[i], renderer, "active", i, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); break; default: renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (column_headers[i], renderer, "text", i, NULL); gtk_tree_view_column_set_sort_column_id (column, i); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); break; } gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (search->list), column); } select = gtk_tree_view_get_selection (GTK_TREE_VIEW (search->list)); gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE); g_signal_connect_swapped (search->list, "button-press-event", G_CALLBACK (giftui_search_list_clicked), search); g_signal_connect (search->list, "row-activated", G_CALLBACK (giftui_search_list_actived), search); return; } /**/ static void giftui_search_disconnect (GiftuiSearch *se) { GtkTreeStore *st; g_return_if_fail (se != NULL); st = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (se->list))); gtk_tree_store_clear (st); return; } /**/ GtkWidget * giftui_search_new (void) { GiftuiSearch *search; search = g_object_new (GIFTUI_TYPE_SEARCH, NULL); giftui_event_register (EVENT_DISCONNECT, 0, search, GIFTUI_REGISTRED_CB (giftui_search_disconnect)); giftui_event_register (EVENT_CLOSE, 0, search, GIFTUI_REGISTRED_CB (giftui_search_disconnect)); giftui_signal_register (PREFS_SEARCH_NETWORKS, GIFTUI_HANDLER_CB (giftui_search_update_networks), search); gtk_widget_show_all (GTK_WIDGET (search)); return GTK_WIDGET (search); } static void giftui_search_dispose (GObject *object) { GiftuiSearch *se = GIFTUI_SEARCH (object); if (se->motion_idle) g_source_remove (se->motion_idle); giftui_search_stop_all (se); giftui_event_unregister_all (se); giftui_signal_unregister_by_data (PREFS_SEARCH_NETWORKS, se); if (se->meta_tip) { gtk_widget_destroy (se->meta_tip->window); g_free (se->meta_tip); se->meta_tip = NULL; } if (se->popup) { gtk_widget_destroy (se->popup); se->popup = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); return; }