chiark / gitweb /
Disobedience: basic support for required/prohibited tags.
[disorder] / disobedience / filter.c
CommitLineData
7791f6cf
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2011 Richard Kettlewell
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/** @file disobedience/filter.c
19 * @brief Track filtering
20 */
21
22#include "disobedience.h"
23
24static GtkWidget *filtering_window;
25
26static struct filter_row {
27 const char *label;
28 const char *pref;
29 GtkWidget *entry;
30} filter_rows[] = {
31 { "Required tags", "required-tags", NULL },
32 { "Prohibited tags", "prohibited-tags", NULL },
33};
34#define NFILTER (sizeof filter_rows / sizeof *filter_rows)
35
36/* Getting values */
37
38/** @brief Called with the latest setting for a row */
39static void filter_get_completed(void *v, const char *err,
40 const char *value) {
41 if(err)
42 popup_protocol_error(0, err);
43 else if(filtering_window) {
44 struct filter_row *row = v;
45 /* Identify unset and empty lists */
46 if(!value)
47 value = "";
48 /* Skip trivial updates (we'll see one as a consequence of each
49 * update we make...) */
50 if(strcmp(gtk_entry_get_text(GTK_ENTRY(row->entry)), value))
51 gtk_entry_set_text(GTK_ENTRY(row->entry), value);
52 }
53}
54
55/** @brief Retrieve the latest setting for @p row */
56static void filter_get(struct filter_row *row) {
57 disorder_eclient_get_global(client, filter_get_completed, row->pref, row);
58}
59
60/** @brief Called when the user changes the contents of some entry */
61static void filter_entry_changed(GtkEditable *editable, gpointer user_data) {
62 struct filter_row *row = user_data;
63 const char *new_value = gtk_entry_get_text(GTK_ENTRY(editable));
64 if(*new_value)
65 disorder_eclient_set_global(client, NULL, row->pref, new_value, row);
66 else
67 disorder_eclient_unset_global(client, NULL, row->pref, row);
68}
69
70/** @brief Display the filtering window */
71void popup_filtering(void) {
72 GtkWidget *label, *table;
73 /* Pop up the window if it already exists */
74 if(filtering_window) {
75 gtk_window_present(GTK_WINDOW(filtering_window));
76 return;
77 }
78 /* Create the window */
79 /* TODO loads of this is very similar to (copied from!) users.c - can we
80 * de-dupe? */
81 filtering_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
82 gtk_widget_set_style(filtering_window, tool_style);
83 gtk_window_set_title(GTK_WINDOW(filtering_window), "Filtering");
84 g_signal_connect(filtering_window, "destroy",
85 G_CALLBACK(gtk_widget_destroyed), &filtering_window);
86 table = gtk_table_new(NFILTER/*rows*/, 2/*cols*/, FALSE/*homogeneous*/);
87 gtk_widget_set_style(table, tool_style);\
88
89 for(size_t n = 0; n < NFILTER; ++n) {
90 label = gtk_label_new(filter_rows[n].label);
91 gtk_widget_set_style(label, tool_style);
92 gtk_misc_set_alignment(GTK_MISC(label), 1/*right*/, 0/*bottom*/);
93 gtk_table_attach(GTK_TABLE(table), label,
94 0, 1, /* left/right_attach */
95 n, n+1, /* top/bottom_attach */
96 GTK_FILL, 0, /* x/yoptions */
97 1, 1); /* x/ypadding */
98 filter_rows[n].entry = gtk_entry_new();
99 gtk_widget_set_style(filter_rows[n].entry, tool_style);
100 gtk_table_attach(GTK_TABLE(table), filter_rows[n].entry,
101 1, 2, /* left/right_attach */
102 n, n+1, /* top/bottom_attach */
103 GTK_FILL, 0, /* x/yoptions */
104 1, 1); /* x/ypadding */
105 g_signal_connect(filter_rows[n].entry, "changed",
106 G_CALLBACK(filter_entry_changed), &filter_rows[n]);
107 filter_get(&filter_rows[n]);
108 }
109
110 gtk_container_add(GTK_CONTAINER(filtering_window), frame_widget(table, NULL));
111 gtk_widget_show_all(filtering_window);
112}
113
114/** @brief Called when any global pref changes */
115static void filtering_global_pref_changed(const char *event,
116 void *eventdata,
117 void *callbackdata) {
118 const char *pref = eventdata;
119 if(!filtering_window)
120 return; /* not paying attention */
121 for(size_t n = 0; n < NFILTER; ++n) {
122 if(!strcmp(pref, filter_rows[n].pref))
123 filter_get(&filter_rows[n]);
124 }
125}
126
127/** @brief Initialize filtering infrastructure */
128void init_filtering() {
129 event_register("global-pref", NULL, filtering_global_pref_changed);
130}