Show search_cb.c syntax highlighted
/*
* $Id: search_cb.c 14708 2007-08-27 17:06:16Z cbiere $
*
* Copyright (c) 2001-2005, Raphael Manfredi, Richard Eckart
*
*----------------------------------------------------------------------
* This file is part of gtk-gnutella.
*
* gtk-gnutella 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.
*
* gtk-gnutella 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 gtk-gnutella; if not, write to the Free Software
* Foundation, Inc.:
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*----------------------------------------------------------------------
*/
/**
* @ingroup gtk
* @file
*
* GUI filtering functions.
*
* @author Raphael Manfredi
* @author Richard Eckart
* @date 2001-2003
*
* @author Raphael Manfredi
* @date 2005
*/
#include "gtk/gui.h"
RCSID("$Id: search_cb.c 14708 2007-08-27 17:06:16Z cbiere $")
#include "search_cb.h"
#include "gtk/bitzi.h"
#include "gtk/columns.h"
#include "gtk/filter_core.h"
#include "gtk/misc.h"
#include "gtk/search_common.h"
#include "gtk/settings.h"
#include "gtk/statusbar.h"
#include "if/gui_property.h"
#include "if/gui_property_priv.h"
#include "if/gnet_property.h"
#include "if/bridge/ui2c.h"
#include "if/core/sockets.h"
#include "lib/atoms.h"
#include "lib/cq.h"
#include "lib/glib-missing.h"
#include "lib/utf8.h"
#include "lib/override.h" /* Must be the last header included */
static record_t *selected_record;
char *
search_gui_details_get_text(GtkWidget *widget)
{
char *text = NULL;
int row;
g_return_val_if_fail(widget, NULL);
row = clist_get_cursor_row(GTK_CLIST(widget));
if (row >= 0 && gtk_clist_get_text(GTK_CLIST(widget), row, 1, &text)) {
return g_strdup(text);
} else {
return NULL;
}
}
/***
*** Private functions
***/
/* Display XML data from the result if any */
static void
search_set_xml_metadata(const record_t *rc)
{
GtkText *xml;
xml = GTK_TEXT(gui_main_window_lookup("text_result_info_xml"));
gtk_text_freeze(xml);
gtk_text_set_point(xml, 0);
gtk_text_forward_delete(xml, gtk_text_get_length(xml));
if (rc) {
gchar *text;
text = rc->xml ? search_xml_indent(rc->xml) : NULL;
gtk_text_set_point(xml, 0);
gtk_text_insert(xml, NULL, NULL, NULL,
text ? lazy_utf8_to_ui_string(text) : "", (-1));
G_FREE_NULL(text);
}
gtk_text_thaw(xml);
}
static GtkCList *clist_search_details;
void
search_gui_clear_details(void)
{
if (clist_search_details) {
gtk_clist_clear(clist_search_details);
}
}
void
search_gui_append_detail(const gchar *name, const gchar *value)
{
const gchar *titles[2];
g_return_if_fail(clist_search_details);
titles[0] = name;
titles[1] = EMPTY_STRING(value);
gtk_clist_append(clist_search_details, (gchar **) titles);
}
/**
* Activates/deactivates buttons and popups based on what is selected
*/
/**
* Set or clear (when rc == NULL) the information about the record.
*/
static void
search_gui_refresh_details(const record_t *rc)
{
if (NULL == clist_search_details) {
static const gchar name[] = "clist_search_details";
clist_search_details = GTK_CLIST(gui_main_window_lookup(name));
gtk_clist_set_column_auto_resize(clist_search_details, 0, TRUE);
}
g_return_if_fail(clist_search_details);
gtk_clist_freeze(clist_search_details);
search_gui_set_details(rc);
gtk_clist_thaw(clist_search_details);
search_set_xml_metadata(rc);
}
record_t *
search_gui_get_record(GtkCTree *ctree, GtkCTreeNode *node)
{
gui_record_t *grc;
/*
* Rows with NULL data can appear when inserting new rows
* because the selection is resynced and the row data cannot
* be set until insertion and therefore also selection syncing
* is done.
* -- Richard, 20/06/2002
*
* Can this really happen???
* -- Richard, 18/04/2004
*/
grc = node ? gtk_ctree_node_get_row_data(ctree, node) : NULL;
return grc ? grc->shared_record : NULL;
}
/**
* Sort search according to selected column
*/
void
on_clist_search_results_click_column(GtkCList *clist, gint column,
gpointer unused_udata)
{
search_t *search;
(void) unused_udata;
g_assert(clist != NULL);
search = search_gui_get_current_search();
if (search == NULL)
return;
/* rotate or initialize search order */
if (column == search->sort_col) {
switch (search->sort_order) {
case SORT_ASC:
search->sort_order = SORT_DESC;
break;
case SORT_DESC:
search->sort_order = SORT_NONE;
break;
case SORT_NONE:
search->sort_order = SORT_ASC;
}
} else {
search->sort_col = column;
search->sort_order = SORT_ASC;
}
search_gui_sort_column(search, column); /* Sort column, draw arrow */
}
static cevent_t *row_selected_ev;
#define ROW_SELECT_TIMEOUT 100 /* milliseconds */
static void
row_selected_expire(cqueue_t *unused_cq, gpointer unused_udata)
{
search_t *search;
(void) unused_cq;
(void) unused_udata;
row_selected_ev = NULL;
search = search_gui_get_current_search();
if (search) {
search_gui_refresh_popup();
search_gui_refresh_details(selected_record);
} else {
search_gui_clear_details();
}
}
static void
selected_row_changed(GtkCTree *ctree)
{
int row;
if (selected_record) {
search_gui_unref_record(selected_record);
selected_record = NULL;
}
row = clist_get_cursor_row(GTK_CLIST(ctree));
if (row >= 0) {
GtkCTreeNode *node;
node = gtk_ctree_node_nth(GTK_CTREE(ctree), row);
selected_record = search_gui_get_record(ctree, GTK_CTREE_NODE(node));
if (selected_record) {
search_gui_ref_record(selected_record);
}
}
if (row_selected_ev) {
cq_resched(callout_queue, row_selected_ev, ROW_SELECT_TIMEOUT);
} else {
row_selected_ev = cq_insert(callout_queue, ROW_SELECT_TIMEOUT,
row_selected_expire, NULL);
}
}
/**
* This function is called when the user selects a row in the
* search results pane. Autoselection takes place here.
*/
void
on_ctree_search_results_select_row(GtkCTree *ctree,
GList *unused_node, gint unused_column, gpointer unused_udata)
{
(void) unused_column;
(void) unused_udata;
(void) unused_node;
selected_row_changed(ctree);
}
/***
*** Search results popup
***/
/**
* Request host browsing for the selected entries.
*/
void
search_gui_browse_selected(void)
{
search_t *search;
GtkCTree *ctree;
GList *selected;
GList *l;;
search = search_gui_get_current_search();
g_assert(search != NULL);
ctree = GTK_CTREE(search->tree);
selected = GTK_CLIST(ctree)->selection;
if (selected == NULL) {
statusbar_gui_message(15, "*** No search result selected! ***");
return;
}
for (l = selected; l != NULL; l = g_list_next(l)) {
GtkCTreeNode *node = l->data;
gui_record_t *grc;
results_set_t *rs;
record_t *rc;
guint32 flags = 0;
if (node == NULL)
break;
grc = gtk_ctree_node_get_row_data(ctree, node);
rc = grc->shared_record;
if (!rc)
continue;
rs = rc->results_set;
flags |= 0 != (rs->status & ST_FIREWALL) ? SOCK_F_PUSH : 0;
flags |= 0 != (rs->status & ST_TLS) ? SOCK_F_TLS : 0;
(void) search_gui_new_browse_host(
rs->hostname, rs->addr, rs->port,
rs->guid, rs->proxies, flags);
}
}
/**
* Given a GList of GtkCTreeNodes, return a new list pointing to the shared
* record contained by the row data.
* List will have to be freed later on.
*/
GSList *
search_cb_collect_ctree_data(GtkCTree *ctree,
GList *node_list, GCompareFunc cfn)
{
GSList *data_list = NULL;
gui_record_t *grc;
record_t *rc;
for (/* empty */; node_list != NULL; node_list = g_list_next(node_list)) {
if (node_list->data != NULL) {
grc = gtk_ctree_node_get_row_data(ctree, node_list->data);
rc = grc->shared_record;
if (!cfn || NULL == g_slist_find_custom(data_list, rc, cfn))
data_list = g_slist_prepend(data_list, rc);
}
}
return g_slist_reverse(data_list);
}
/**
* Queue a bitzi queries from the search context menu
*/
void
on_popup_search_metadata_activate(GtkMenuItem *unused_menuitem,
gpointer unused_udata)
{
GList *node_list;
GSList *data_list;
search_t *search;
guint32 bitzi_debug;
(void) unused_menuitem;
(void) unused_udata;
search = search_gui_get_current_search();
g_assert(search != NULL);
gtk_clist_freeze(GTK_CLIST(search->tree));
node_list = g_list_copy(GTK_CLIST(search->tree)->selection);
data_list = search_cb_collect_ctree_data(GTK_CTREE(search->tree),
node_list, gui_record_sha1_eq);
/* Make sure the column is actually visible. */
{
static const gint min_width = 80;
GtkCList *clist = GTK_CLIST(search->tree);
gtk_clist_set_column_visibility(clist, c_sr_meta, TRUE);
if (clist->column[c_sr_meta].width < min_width)
gtk_clist_set_column_width(clist, c_sr_meta, min_width);
}
/* Queue up our requests */
gnet_prop_get_guint32_val(PROP_BITZI_DEBUG, &bitzi_debug);
if (bitzi_debug)
g_message("on_popup_search_metadata_activate: %d items, %p",
g_slist_position(data_list, g_slist_last(data_list)) + 1,
cast_to_gconstpointer(data_list));
G_SLIST_FOREACH(data_list, search_gui_queue_bitzi_by_sha1);
gtk_clist_thaw(GTK_CLIST(search->tree));
g_slist_free(data_list);
g_list_free(node_list);
}
void
on_popup_search_copy_magnet_activate(GtkMenuItem *unused_item,
gpointer unused_udata)
{
search_t *search;
(void) unused_item;
(void) unused_udata;
search = search_gui_get_current_search();
g_return_if_fail(search);
if (selected_record) {
char *magnet = search_gui_get_magnet(search, selected_record);
clipboard_set_text(gui_main_window(), magnet);
G_FREE_NULL(magnet);
}
}
void
search_gui_callbacks_shutdown(void)
{
/*
* Remove delayed callbacks
*/
cq_cancel(callout_queue, &row_selected_ev);
search_gui_clear_details();
if (selected_record) {
search_gui_unref_record(selected_record);
selected_record = NULL;
}
}
/* -*- mode: cc-mode; tab-width:4; -*- */
/* vi: set ts=4 sw=4 cindent: */
See more files for this project here