changeset 2795:4c9db0b2194f

added strcasestr implementation; improved searching and updating
author Calin Crisan ccrisan@gmail.com
date Thu, 10 Jul 2008 01:40:57 +0300
parents f9c6a9cb442e
children 2ce16807a088
files src/streambrowser/gui/streambrowser_win.c src/streambrowser/streambrowser.c
diffstat 2 files changed, 162 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/src/streambrowser/gui/streambrowser_win.c	Wed Jul 09 22:52:56 2008 +0300
+++ b/src/streambrowser/gui/streambrowser_win.c	Thu Jul 10 01:40:57 2008 +0300
@@ -1,5 +1,7 @@
 
+#include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
@@ -10,14 +12,14 @@
 
 typedef struct {
 
-	streamdir_t*		streamdir;
+	streamdir_t*	streamdir;
 	GtkWidget*		table;
 	GtkWidget*		tree_view;
 
 } streamdir_gui_t;
 
 
-void				(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
+void					(* update_function) (streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
 
 static GtkWidget*		gtk_label_new_with_icon(gchar *icon_filename, gchar *label_text);
 static GtkWidget*		gtk_streamdir_tree_view_new();
@@ -29,20 +31,22 @@
 static gboolean			on_search_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data);
 static gboolean			on_tree_view_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data);
 
-static streamdir_gui_t*		find_streamdir_gui_by_name(gchar *name);
-static streamdir_gui_t*		find_streamdir_gui_by_tree_view(GtkTreeView *tree_view);
-static streamdir_gui_t*		find_streamdir_gui_by_table(GtkTable *table);
-static streamdir_gui_t*		find_streamdir_gui_by_streamdir(streamdir_t *streamdir);
+static streamdir_gui_t*	find_streamdir_gui_by_name(gchar *name);
+static streamdir_gui_t*	find_streamdir_gui_by_tree_view(GtkTreeView *tree_view);
+static streamdir_gui_t*	find_streamdir_gui_by_table(GtkTable *table);
+static streamdir_gui_t*	find_streamdir_gui_by_streamdir(streamdir_t *streamdir);
 static gboolean			tree_view_search_equal_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer data);
 
+static gboolean			mystrcasestr(const char *haystack, const char *needle);
+
 
 static GtkWidget*		notebook;
 static GtkWidget*		search_entry;
 static GtkWidget*		add_button;
 static GtkWidget*		streambrowser_window;
 static GList*			streamdir_gui_list;
-static GtkCellRenderer*		cell_renderer_pixbuf;
-static GtkCellRenderer*		cell_renderer_text;
+static GtkCellRenderer*	cell_renderer_pixbuf;
+static GtkCellRenderer*	cell_renderer_text;
 
 
 void streambrowser_win_init()
@@ -238,7 +242,9 @@
 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), TRUE);
 	gtk_tree_view_set_search_entry(GTK_TREE_VIEW(tree_view), GTK_ENTRY(search_entry));
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(tree_view), tree_view_search_equal_func, NULL, NULL);
+	gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_view), 1);
 	g_signal_connect(G_OBJECT(tree_view), "key-press-event", G_CALLBACK(on_tree_view_key_pressed), NULL);
+	g_signal_connect(G_OBJECT(tree_view), "cursor-changed", G_CALLBACK(on_tree_view_cursor_changed), NULL);
 
 	GtkTreeViewColumn *column = gtk_tree_view_column_new();
 	gtk_tree_view_column_pack_start(column, cell_renderer_pixbuf, TRUE);
@@ -260,8 +266,6 @@
 	gtk_tree_view_column_set_title(column, _("Now playing"));
 	gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
 
-	g_signal_connect(G_OBJECT(tree_view), "cursor-changed", G_CALLBACK(on_tree_view_cursor_changed), NULL);
-
 	return tree_view;
 }
 
@@ -297,10 +301,11 @@
 static gboolean on_tree_view_cursor_changed(GtkTreeView *tree_view, gpointer data)
 {
 	GtkTreePath *path;
-	GtkTreeViewColumn *focus_column;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
 
 	/* obtain the current category */
-	gtk_tree_view_get_cursor(tree_view, &path, &focus_column);
+	gtk_tree_view_get_cursor(tree_view, &path, NULL);
 	
 	if (path == NULL)
 		return TRUE;
@@ -311,7 +316,10 @@
 		return TRUE;
 	}
 	
-	if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree_view), path)) {
+	model = gtk_tree_view_get_model(tree_view);
+	gtk_tree_model_get_iter(model, &iter, path);
+	
+	if (gtk_tree_model_iter_has_child(model, &iter)) {
 		gtk_tree_path_free(path);
 		return TRUE;
 	}
@@ -327,9 +335,6 @@
 	/* issue an update on the current category */	
 	update_function(streamdir_gui->streamdir, category_get_by_index(streamdir_gui->streamdir, category_index), NULL);
 	
-	/* clear the search box */
-	gtk_entry_set_text(GTK_ENTRY(search_entry), "");
-
 	return TRUE;
 }
 
@@ -365,6 +370,7 @@
 	category_t *category = category_get_by_index(streamdir_gui->streamdir, category_index);
 	streaminfo_t *streaminfo = streaminfo_get_by_index(category, streaminfo_index);
 	
+	gtk_entry_set_text(GTK_ENTRY(search_entry), "");
 	update_function(streamdir, category, streaminfo);
 
 	return TRUE;
@@ -372,40 +378,51 @@
 
 static gboolean on_search_entry_key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
 {
-	if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
+	if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
 		on_add_button_clicked(GTK_BUTTON(add_button), NULL);
+		return FALSE;
+	}
+
+	if (event->keyval == GDK_Escape) {
+		gtk_entry_set_text(GTK_ENTRY(search_entry), "");
+		return FALSE;
+	}
 	
-	/* todo: remove this
+	/* todo : remove this
 	GtkWidget *table = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
 	streamdir_gui_t *streamdir_gui = find_streamdir_gui_by_table(GTK_TABLE(table));
 	if (streamdir_gui == NULL)
 		return FALSE;
 
-	GtkWidget *tree_view = streamdir_gui->tree_view;
+	GtkTreeView *tree_view = GTK_TREE_VIEW(streamdir_gui->tree_view);
+	GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
 	GtkTreeIter iter;
-	gboolean is_expanded = FALSE;
-	GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)));
 	GtkTreePath *path;
-	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
+	const gchar *key = gtk_entry_get_text(GTK_ENTRY(search_entry));
+	
+	if (!gtk_tree_model_get_iter_first(model, &iter))
 		return FALSE;
 		
-	while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) {
-		path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
-		
-		if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree_view), path)) {
-			is_expanded = TRUE;
-			break;
+	while (gtk_tree_model_iter_next(model, &iter)) {
+		GValue value = {0, };
+
+		gtk_tree_model_get_value(model, &iter, 1, &value);
+		const gchar *string = g_value_get_string(&value);
+	
+		if (string == NULL || string[0] == '\0' || key == NULL || key[0] == '\0')
+			return FALSE;
+
+		if (mystrcasestr(string, key)) {		gtk_entry_set_text(GTK_ENTRY(search_entry), "");
+
+			path = gtk_tree_model_get_path(model, &iter);	
+			gtk_tree_view_set_cursor(tree_view, path, NULL, FALSE);
+			gtk_tree_path_free(path);
 		}
-		
-		gtk_tree_path_free(path);
-	}
 
-	if (!is_expanded)
-		gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_view), );
-	else
-		gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree_view), 1);
+		g_value_unset(&value);		
+	}
 	*/
-	
+
 	return FALSE;
 }
 
@@ -485,11 +502,35 @@
 	gtk_tree_model_get_value(model, iter, column, &value);
 	const gchar *string = g_value_get_string(&value);
 	
-	// todo: why do I get "warning: implicit declaration" for strcasestr !?
-	ret = ((char *) strcasestr(string, key) == NULL);
+	if (string == NULL || string[0] == '\0' || key == NULL || key[0] == '\0')
+		ret = TRUE;
+
+	ret = !mystrcasestr(string, key);
 	
 	g_value_unset(&value);
 
 	return ret;
 }
 
+static gboolean mystrcasestr(const char *haystack, const char *needle)
+{
+	int len_h = strlen(haystack) + 1;
+	int len_n = strlen(needle) + 1;
+	int i;
+	
+	char *upper_h = malloc(len_h);
+	char *upper_n = malloc(len_n);
+	
+	for (i = 0; i < len_h; i++)
+		upper_h[i] = toupper(haystack[i]);
+	for (i = 0; i < len_n; i++)
+		upper_n[i] = toupper(needle[i]);
+	
+	char *p = strstr(upper_h, upper_n);
+
+	free(upper_h);
+	free(upper_n);
+	
+	return (gboolean) p;
+}
+
--- a/src/streambrowser/streambrowser.c	Wed Jul 09 22:52:56 2008 +0300
+++ b/src/streambrowser/streambrowser.c	Thu Jul 10 01:40:57 2008 +0300
@@ -29,7 +29,7 @@
 static void config_save();
 
 static void streamdir_update(streamdir_t *streamdir, category_t *category, streaminfo_t *streaminfo);
-static gpointer update_thread_core(update_thread_data_t *data);
+static gpointer update_thread_core(gpointer user_data);
 static void streaminfo_add_to_playlist(streaminfo_t *streaminfo);
 static void on_plugin_services_menu_item_click();
 
@@ -241,13 +241,16 @@
     if (update_thread_count >= MAX_UPDATE_THREADS) {
         debug("another %d streamdir updates are pending, this request will be dropped\n", update_thread_count);
     }
-    else
+    else {
+        g_mutex_lock(update_thread_mutex);
+            
+    	/* do we have a running thread? */
         if (update_thread_count > 0) {
             int i;
             gboolean exists = FALSE;
             update_thread_data_t *update_thread_data;
 
-            g_mutex_lock(update_thread_mutex);
+            /* search for another identic update request */
             for (i = 0; i < g_queue_get_length(update_thread_data_queue); i++) {
                 update_thread_data = g_queue_peek_nth(update_thread_data_queue, i);
                 if (update_thread_data->streamdir == streamdir &&
@@ -257,105 +260,115 @@
                     break;
                 }
             }
-            g_mutex_unlock(update_thread_mutex);
-
+            
+            /* if no other similar request exists, we enqueue it */
             if (!exists) {
                 debug("another %d streamdir updates are pending, this request will be queued\n", update_thread_count);
 
-                g_mutex_lock(update_thread_mutex);
-
                 update_thread_data = g_malloc(sizeof(update_thread_data_t));
 
                 update_thread_data->streamdir = streamdir;
                 update_thread_data->category = category;
                 update_thread_data->streaminfo = streaminfo;
+ 
                 g_queue_push_tail(update_thread_data_queue, update_thread_data);
-
                 update_thread_count++;
-
-                g_mutex_unlock(update_thread_mutex);
             }
             else {
                 debug("this request is already present in the queue, dropping\n");          
             }
         }
+        /* no thread is currently running, we start one */
         else {
+        	debug("no other streamdir updates are pending, starting to process this request immediately\n");
+        
             update_thread_data_t *data = g_malloc(sizeof(update_thread_data_t));
 
             data->streamdir = streamdir;
             data->category = category;
             data->streaminfo = streaminfo;
+ 
+            g_queue_push_tail(update_thread_data_queue, data);
+            update_thread_count++;
 
-            g_thread_create((GThreadFunc) update_thread_core, data, FALSE, NULL);
+			g_thread_create((GThreadFunc) update_thread_core, NULL, FALSE, NULL);
         }
+
+        g_mutex_unlock(update_thread_mutex);
+    }
 }
 
-static gpointer update_thread_core(update_thread_data_t *data)
+static gpointer update_thread_core(gpointer user_data)
 {
-    g_mutex_lock(update_thread_mutex);
-    update_thread_count++;
-    g_mutex_unlock(update_thread_mutex);
+	debug("entering update thread core\n");
+
+	/* try to get the last item in the queue */
+	g_mutex_lock(update_thread_mutex);
+	update_thread_data_t *data = NULL;
+	if (update_thread_count > 0) {
+		data = g_queue_pop_head(update_thread_data_queue);
+	}
+	g_mutex_unlock(update_thread_mutex);
 
-    /* update a streaminfo - that is - add this streaminfo to playlist */
-    if (data->streaminfo != NULL) {
-        streaminfo_add_to_playlist(data->streaminfo);
-    }
-    /* update a category */
-    else if (data->category != NULL) {
-        /* shoutcast */
-        if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
-        	gdk_threads_enter();
-			streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
-        	gdk_threads_leave();
-        	
-            shoutcast_category_fetch(data->category);
+	/* repetitively process the queue elements, until queue is empty */
+	while (data != NULL && update_thread_count > 0) {
+	    /* update a streaminfo - that is - add this streaminfo to playlist */
+		if (data->streaminfo != NULL) {
+		    streaminfo_add_to_playlist(data->streaminfo);
+		}
+		/* update a category */
+		else if (data->category != NULL) {
+		    /* shoutcast */
+		    if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
+		    	gdk_threads_enter();
+				streambrowser_win_set_category_state(data->streamdir, data->category, TRUE);
+		    	gdk_threads_leave();
+		    	
+		        shoutcast_category_fetch(data->category);
 
-            gdk_threads_enter();
-            streambrowser_win_set_category(data->streamdir, data->category);
-			streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
-            gdk_threads_leave();
-        }
-    }
-    /* update a streamdir */
-    else if (data->streamdir != NULL) {
-        /* shoutcast */
-        if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
-            streamdir_t *streamdir = shoutcast_streamdir_fetch();
-            if (streamdir != NULL) {
-                gdk_threads_enter();
-                streambrowser_win_set_streamdir(streamdir, SHOUTCAST_ICON);
-                gdk_threads_leave();
-            }
-        }
-    }
-    /* update all streamdirs */
-    else {
-        /* shoutcast */
-        streamdir_t *shoutcast_streamdir = shoutcast_streamdir_fetch();
-        if (shoutcast_streamdir != NULL) {
-            gdk_threads_enter();
-            streambrowser_win_set_streamdir(shoutcast_streamdir, SHOUTCAST_ICON);
-            gdk_threads_leave();
-        }
-    }
+		        gdk_threads_enter();
+		        streambrowser_win_set_category(data->streamdir, data->category);
+				streambrowser_win_set_category_state(data->streamdir, data->category, FALSE);
+		        gdk_threads_leave();
+		    }
+		}
+		/* update a streamdir */
+		else if (data->streamdir != NULL) {
+		    /* shoutcast */
+		    if (strncmp(data->streamdir->name, SHOUTCAST_NAME, strlen(SHOUTCAST_NAME)) == 0) {
+		        streamdir_t *streamdir = shoutcast_streamdir_fetch();
+		        if (streamdir != NULL) {
+		            gdk_threads_enter();
+		            streambrowser_win_set_streamdir(streamdir, SHOUTCAST_ICON);
+		            gdk_threads_leave();
+		        }
+		    }
+		}
+		/* update all streamdirs */
+		else {
+		    /* shoutcast */
+		    streamdir_t *shoutcast_streamdir = shoutcast_streamdir_fetch();
+		    if (shoutcast_streamdir != NULL) {
+		        gdk_threads_enter();
+		        streambrowser_win_set_streamdir(shoutcast_streamdir, SHOUTCAST_ICON);
+		        gdk_threads_leave();
+		    }
+		}
 
-    g_free(data);
-
-    /* check to see if there are queued update requests */
+		g_free(data);
 
-    data = NULL;
-    g_mutex_lock(update_thread_mutex);
-    update_thread_count--;
+		g_mutex_lock(update_thread_mutex);
+		update_thread_count--;	
 
-    if (update_thread_count > 0) {
-        data = g_queue_pop_head(update_thread_data_queue);
+		/* try to get the last item in the queue */
+		if (update_thread_count > 0)
+			data = g_queue_pop_head(update_thread_data_queue);
+		else
+			data = NULL;
+		g_mutex_unlock(update_thread_mutex);
+	}
 
-        update_thread_count--;
-    }
-    g_mutex_unlock(update_thread_mutex);
-
-    if (data != NULL)
-        update_thread_core(data);
+	debug("leaving update thread core\n");
 
     return NULL;
 }