chiark / gitweb /
Switch to GPL v3
[disorder] / disobedience / queue-menu.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2006-2008 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 #include "disobedience.h"
19 #include "popup.h"
20 #include "queue-generic.h"
21
22 /* Select All */
23
24 int ql_selectall_sensitive(void *extra) {
25   struct queuelike *ql = extra;
26   return !!ql->q;
27 }
28
29 void ql_selectall_activate(GtkMenuItem attribute((unused)) *menuitem,
30                            gpointer user_data) {
31   struct queuelike *ql = user_data;
32
33   gtk_tree_selection_select_all(ql->selection);
34 }
35
36 /* Select None */
37
38 int ql_selectnone_sensitive(void *extra) {
39   struct queuelike *ql = extra;
40   return gtk_tree_selection_count_selected_rows(ql->selection) > 0;
41 }
42
43 void ql_selectnone_activate(GtkMenuItem attribute((unused)) *menuitem,
44                             gpointer user_data) {
45   struct queuelike *ql = user_data;
46
47   gtk_tree_selection_unselect_all(ql->selection);
48 }
49
50 /* Properties */
51
52 int ql_properties_sensitive(void *extra) {
53   struct queuelike *ql = extra;
54   return gtk_tree_selection_count_selected_rows(ql->selection) > 0;
55 }
56
57 void ql_properties_activate(GtkMenuItem attribute((unused)) *menuitem,
58                             gpointer user_data) {
59   struct queuelike *ql = user_data;
60   struct vector v[1];
61   GtkTreeIter iter[1];
62
63   vector_init(v);
64   gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ql->store), iter);
65   for(struct queue_entry *q = ql->q; q; q = q->next) {
66     if(gtk_tree_selection_iter_is_selected(ql->selection, iter))
67       vector_append(v, (char *)q->track);
68     gtk_tree_model_iter_next(GTK_TREE_MODEL(ql->store), iter);
69   }
70   if(v->nvec)
71     properties(v->nvec, (const char **)v->vec);
72 }
73
74 /* Scratch */
75
76 int ql_scratch_sensitive(void attribute((unused)) *extra) {
77   return !!(last_state & DISORDER_PLAYING)
78     && right_scratchable(last_rights, config->username, playing_track);
79 }
80
81 static void ql_scratch_completed(void attribute((unused)) *v,
82                                  const char *err) {
83   if(err)
84     popup_protocol_error(0, err);
85 }
86
87 void ql_scratch_activate(GtkMenuItem attribute((unused)) *menuitem,
88                          gpointer attribute((unused)) user_data) {
89   disorder_eclient_scratch_playing(client, ql_scratch_completed, 0);
90 }
91
92 /* Remove */
93
94 static void ql_remove_sensitive_callback(GtkTreeModel *model,
95                                          GtkTreePath attribute((unused)) *path,
96                                          GtkTreeIter *iter,
97                                          gpointer data) {
98   struct queue_entry *q = ql_iter_to_q(model, iter);
99   const int removable = (q != playing_track
100                          && right_removable(last_rights, config->username, q));
101   int *const counts = data;
102   ++counts[removable];
103 }
104
105 int ql_remove_sensitive(void *extra) {
106   struct queuelike *ql = extra;
107   int counts[2] = { 0, 0 };
108   gtk_tree_selection_selected_foreach(ql->selection,
109                                       ql_remove_sensitive_callback,
110                                       counts);
111   /* Remove will work if we have at least some removable tracks selected, and
112    * no unremovable ones */
113   return counts[1] > 0 && counts[0] == 0;
114 }
115
116 static void ql_remove_completed(void attribute((unused)) *v,
117                                 const char *err) {
118   if(err)
119     popup_protocol_error(0, err);
120 }
121
122 static void ql_remove_activate_callback(GtkTreeModel *model,
123                                         GtkTreePath attribute((unused)) *path,
124                                         GtkTreeIter *iter,
125                                         gpointer attribute((unused)) data) {
126   struct queue_entry *q = ql_iter_to_q(model, iter);
127
128   if(q != playing_track)
129     disorder_eclient_remove(client, q->id, ql_remove_completed, q);
130 }
131
132 void ql_remove_activate(GtkMenuItem attribute((unused)) *menuitem,
133                         gpointer user_data) {
134   struct queuelike *ql = user_data;
135   gtk_tree_selection_selected_foreach(ql->selection,
136                                       ql_remove_activate_callback,
137                                       0);
138 }
139
140 /* Play */
141
142 int ql_play_sensitive(void *extra) {
143   struct queuelike *ql = extra;
144   return (last_rights & RIGHT_PLAY)
145     && gtk_tree_selection_count_selected_rows(ql->selection) > 0;
146 }
147
148 static void ql_play_completed(void attribute((unused)) *v, const char *err) {
149   if(err)
150     popup_protocol_error(0, err);
151 }
152
153 static void ql_play_activate_callback(GtkTreeModel *model,
154                                       GtkTreePath attribute((unused)) *path,
155                                       GtkTreeIter *iter,
156                                       gpointer attribute((unused)) data) {
157   struct queue_entry *q = ql_iter_to_q(model, iter);
158
159   disorder_eclient_play(client, q->track, ql_play_completed, q);
160 }
161
162 void ql_play_activate(GtkMenuItem attribute((unused)) *menuitem,
163                          gpointer user_data) {
164   struct queuelike *ql = user_data;
165   gtk_tree_selection_selected_foreach(ql->selection,
166                                       ql_play_activate_callback,
167                                       0);
168 }
169
170 /** @brief Called when a button is released over a queuelike */
171 gboolean ql_button_release(GtkWidget *widget,
172                            GdkEventButton *event,
173                            gpointer user_data) {
174   struct queuelike *ql = user_data;
175
176   if(event->type == GDK_BUTTON_PRESS
177      && event->button == 3) {
178     /* Right button click. */
179     ensure_selected(GTK_TREE_VIEW(widget), event);
180     popup(&ql->menu, event, ql->menuitems, ql->nmenuitems, ql);
181     return TRUE;                        /* hide the click from other widgets */
182   }
183
184   return FALSE;
185 }
186
187 struct tabtype *ql_tabtype(struct queuelike *ql) {
188   static const struct tabtype queuelike_tabtype = {
189     ql_properties_sensitive,
190     ql_selectall_sensitive,
191     ql_selectnone_sensitive,
192     ql_properties_activate,
193     ql_selectall_activate,
194     ql_selectnone_activate,
195     0,
196     0
197   };
198
199   ql->tabtype = queuelike_tabtype;
200   ql->tabtype.extra = ql;
201   return &ql->tabtype;
202 }
203
204 /*
205 Local Variables:
206 c-basic-offset:2
207 comment-column:40
208 fill-column:79
209 indent-tabs-mode:nil
210 End:
211 */