From: Richard Kettlewell Date: Sat, 30 Jul 2011 17:51:36 +0000 (+0100) Subject: Disobedience: basic support for required/prohibited tags. X-Git-Tag: branchpoint-5.1~37^2~7 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/7791f6cf8bd47fb571340b4dba7fad8185b092a1 Disobedience: basic support for required/prohibited tags. --- diff --git a/disobedience/Makefile.am b/disobedience/Makefile.am index 0f6bcaa..49a0c4e 100644 --- a/disobedience/Makefile.am +++ b/disobedience/Makefile.am @@ -28,7 +28,7 @@ disobedience_SOURCES=disobedience.h disobedience.c client.c queue.c \ control.c properties.c menu.c log.c progress.c login.c rtp.c \ help.c ../lib/memgc.c settings.c users.c lookup.c choose.h \ popup.h playlists.c multidrag.c multidrag.h autoscroll.c \ - autoscroll.h + autoscroll.h filter.c disobedience_LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBGC) $(LIBGCRYPT) \ $(LIBASOUND) $(COREAUDIO) $(LIBDB) $(LIBICONV) disobedience_LDFLAGS=$(GTK_LIBS) diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index 719eea4..81de1f6 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -237,6 +237,11 @@ void manage_users(void); void popup_help(const char *what); +/* Filtering */ + +void popup_filtering(void); +void init_filtering(void); + /* RTP */ int rtp_running(void); diff --git a/disobedience/filter.c b/disobedience/filter.c new file mode 100644 index 0000000..12f6cea --- /dev/null +++ b/disobedience/filter.c @@ -0,0 +1,130 @@ +/* + * This file is part of DisOrder. + * Copyright (C) 2011 Richard Kettlewell + * + * 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 3 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, see . + */ +/** @file disobedience/filter.c + * @brief Track filtering + */ + +#include "disobedience.h" + +static GtkWidget *filtering_window; + +static struct filter_row { + const char *label; + const char *pref; + GtkWidget *entry; +} filter_rows[] = { + { "Required tags", "required-tags", NULL }, + { "Prohibited tags", "prohibited-tags", NULL }, +}; +#define NFILTER (sizeof filter_rows / sizeof *filter_rows) + +/* Getting values */ + +/** @brief Called with the latest setting for a row */ +static void filter_get_completed(void *v, const char *err, + const char *value) { + if(err) + popup_protocol_error(0, err); + else if(filtering_window) { + struct filter_row *row = v; + /* Identify unset and empty lists */ + if(!value) + value = ""; + /* Skip trivial updates (we'll see one as a consequence of each + * update we make...) */ + if(strcmp(gtk_entry_get_text(GTK_ENTRY(row->entry)), value)) + gtk_entry_set_text(GTK_ENTRY(row->entry), value); + } +} + +/** @brief Retrieve the latest setting for @p row */ +static void filter_get(struct filter_row *row) { + disorder_eclient_get_global(client, filter_get_completed, row->pref, row); +} + +/** @brief Called when the user changes the contents of some entry */ +static void filter_entry_changed(GtkEditable *editable, gpointer user_data) { + struct filter_row *row = user_data; + const char *new_value = gtk_entry_get_text(GTK_ENTRY(editable)); + if(*new_value) + disorder_eclient_set_global(client, NULL, row->pref, new_value, row); + else + disorder_eclient_unset_global(client, NULL, row->pref, row); +} + +/** @brief Display the filtering window */ +void popup_filtering(void) { + GtkWidget *label, *table; + /* Pop up the window if it already exists */ + if(filtering_window) { + gtk_window_present(GTK_WINDOW(filtering_window)); + return; + } + /* Create the window */ + /* TODO loads of this is very similar to (copied from!) users.c - can we + * de-dupe? */ + filtering_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_style(filtering_window, tool_style); + gtk_window_set_title(GTK_WINDOW(filtering_window), "Filtering"); + g_signal_connect(filtering_window, "destroy", + G_CALLBACK(gtk_widget_destroyed), &filtering_window); + table = gtk_table_new(NFILTER/*rows*/, 2/*cols*/, FALSE/*homogeneous*/); + gtk_widget_set_style(table, tool_style);\ + + for(size_t n = 0; n < NFILTER; ++n) { + label = gtk_label_new(filter_rows[n].label); + gtk_widget_set_style(label, tool_style); + gtk_misc_set_alignment(GTK_MISC(label), 1/*right*/, 0/*bottom*/); + gtk_table_attach(GTK_TABLE(table), label, + 0, 1, /* left/right_attach */ + n, n+1, /* top/bottom_attach */ + GTK_FILL, 0, /* x/yoptions */ + 1, 1); /* x/ypadding */ + filter_rows[n].entry = gtk_entry_new(); + gtk_widget_set_style(filter_rows[n].entry, tool_style); + gtk_table_attach(GTK_TABLE(table), filter_rows[n].entry, + 1, 2, /* left/right_attach */ + n, n+1, /* top/bottom_attach */ + GTK_FILL, 0, /* x/yoptions */ + 1, 1); /* x/ypadding */ + g_signal_connect(filter_rows[n].entry, "changed", + G_CALLBACK(filter_entry_changed), &filter_rows[n]); + filter_get(&filter_rows[n]); + } + + gtk_container_add(GTK_CONTAINER(filtering_window), frame_widget(table, NULL)); + gtk_widget_show_all(filtering_window); +} + +/** @brief Called when any global pref changes */ +static void filtering_global_pref_changed(const char *event, + void *eventdata, + void *callbackdata) { + const char *pref = eventdata; + if(!filtering_window) + return; /* not paying attention */ + for(size_t n = 0; n < NFILTER; ++n) { + if(!strcmp(pref, filter_rows[n].pref)) + filter_get(&filter_rows[n]); + } +} + +/** @brief Initialize filtering infrastructure */ +void init_filtering() { + event_register("global-pref", NULL, filtering_global_pref_changed); +} diff --git a/disobedience/log.c b/disobedience/log.c index 71d2af0..2fd04a1 100644 --- a/disobedience/log.c +++ b/disobedience/log.c @@ -48,6 +48,8 @@ static void log_playlist_modified(void *v, const char *playlist, const char *sharing); static void log_playlist_deleted(void *v, const char *playlist); +static void log_global_pref(void *v, + const char *name, const char *value); /** @brief Callbacks for server state monitoring */ const disorder_eclient_log_callbacks log_callbacks = { @@ -69,6 +71,7 @@ const disorder_eclient_log_callbacks log_callbacks = { .playlist_created = log_playlist_created, .playlist_modified = log_playlist_modified, .playlist_deleted = log_playlist_deleted, + .global_pref = log_global_pref, }; /** @brief Update everything */ @@ -238,6 +241,12 @@ static void log_playlist_deleted(void attribute((unused)) *v, event_raise("playlist-deleted", (void *)playlist); } +static void log_global_pref(void attribute((unused)) *v, + const char *name, + const char attribute((unused)) *value) { + event_raise("global-pref", (void *)name); +} + /* Local Variables: c-basic-offset:2 diff --git a/disobedience/menu.c b/disobedience/menu.c index f54c2a3..946361d 100644 --- a/disobedience/menu.c +++ b/disobedience/menu.c @@ -360,6 +360,14 @@ GtkWidget *menubar(GtkWidget *w) { (char *)"", /* item_type */ 0 /* extra_data */ }, + { + (char *)"/Control/Filtering", /* path */ + (char *)"F", /* accelerator */ + popup_filtering, /* callback */ + 0, /* callback_action */ + 0, /* item_type */ + 0 /* extra_data */ + }, { (char *)"/Control/Activate playlist", /* path */ 0, /* accelerator */