23a56d5b418b6d11edc6f2107ee49c67fbb9e493
1 /*
2 * (c) 2005 by Kalle Wallin <kaw@linux.se>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 */
19 #include "ncmpc.h"
20 #include "options.h"
21 #include "support.h"
22 #include "mpdclient.h"
23 #include "utils.h"
24 #include "strfsong.h"
25 #include "command.h"
26 #include "screen.h"
27 #include "screen_utils.h"
28 #include "screen_browser.h"
29 #include "gcc.h"
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <glib.h>
35 #include <ncurses.h>
37 #define BUFSIZE 1024
39 typedef enum { LIST_ARTISTS, LIST_ALBUMS, LIST_SONGS } artist_mode_t;
41 static artist_mode_t mode = LIST_ARTISTS;
42 static char *artist = NULL;
43 static char *album = NULL;
44 static unsigned metalist_length = 0;
45 static GList *metalist = NULL;
47 static struct screen_browser browser;
49 static gint
50 compare_utf8(gconstpointer s1, gconstpointer s2)
51 {
52 char *key1, *key2;
53 int n;
55 key1 = g_utf8_collate_key(s1,-1);
56 key2 = g_utf8_collate_key(s2,-1);
57 n = strcmp(key1,key2);
58 g_free(key1);
59 g_free(key2);
60 return n;
61 }
63 /* list_window callback */
64 static const char *
65 artist_lw_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data)
66 {
67 static char buf[BUFSIZE];
68 char *str, *str_utf8;
70 if ((str_utf8 = (char *)g_list_nth_data(metalist, idx)) == NULL)
71 return NULL;
73 str = utf8_to_locale(str_utf8);
74 g_snprintf(buf, BUFSIZE, "[%s]", str);
75 g_free(str);
77 return buf;
78 }
80 static void
81 paint(mpdclient_t *c);
83 static void
84 artist_repaint(void)
85 {
86 paint(NULL);
87 wrefresh(browser.lw->w);
88 }
90 static void
91 artist_repaint_if_active(void)
92 {
93 if (get_cur_mode_id() == 2) /* XXX don't use the literal number */
94 artist_repaint();
95 }
97 /* the playlist have been updated -> fix highlights */
98 static void
99 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
100 {
101 browser_playlist_changed(&browser, c, event, data);
103 artist_repaint_if_active();
104 }
106 /* fetch artists/albums/songs from mpd */
107 static void
108 update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
109 {
110 g_free(artist);
111 g_free(album);
112 artist = NULL;
113 album = NULL;
115 if (metalist)
116 metalist = string_list_free(metalist);
117 if (browser.filelist) {
118 mpdclient_remove_playlist_callback(c, playlist_changed_callback);
119 filelist_free(browser.filelist);
120 browser.filelist = NULL;
121 }
123 if (m_album) {
124 /* retreive songs... */
125 artist = m_artist;
126 album = m_album;
127 if (album[0] == 0) {
128 album = g_strdup(_("All tracks"));
129 browser.filelist =
130 mpdclient_filelist_search_utf8(c, TRUE,
131 MPD_TABLE_ARTIST,
132 artist);
133 } else
134 browser.filelist =
135 mpdclient_filelist_search_utf8(c, TRUE,
136 MPD_TABLE_ALBUM,
137 album);
138 if (browser.filelist == NULL)
139 browser.filelist = filelist_new(NULL);
141 /* add a dummy entry for ".." */
142 filelist_prepend(browser.filelist, NULL);
144 /* install playlist callback and fix highlights */
145 sync_highlights(c, browser.filelist);
146 mpdclient_install_playlist_callback(c, playlist_changed_callback);
147 mode = LIST_SONGS;
148 } else if (m_artist) {
149 /* retreive albums... */
151 artist = m_artist;
152 metalist = mpdclient_get_albums_utf8(c, m_artist);
153 /* sort list */
154 metalist = g_list_sort(metalist, compare_utf8);
155 /* add a dummy entry for ".." */
156 metalist = g_list_insert(metalist, g_strdup(".."), 0);
157 /* add a dummy entry for all songs */
158 metalist = g_list_insert(metalist, g_strdup(_("All tracks")), -1);
159 mode = LIST_ALBUMS;
160 } else {
161 /* retreive artists... */
163 metalist = mpdclient_get_artists_utf8(c);
164 /* sort list */
165 metalist = g_list_sort(metalist, compare_utf8);
166 mode = LIST_ARTISTS;
167 }
168 metalist_length = g_list_length(metalist);
169 }
171 /* db updated */
172 static void
173 browse_callback(mpdclient_t *c, int event, mpd_unused gpointer data)
174 {
175 switch(event) {
176 case BROWSE_DB_UPDATED:
177 D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
178 update_metalist(c, g_strdup(artist), g_strdup(album));
179 break;
180 default:
181 break;
182 }
184 artist_repaint_if_active();
185 }
187 static void
188 init(WINDOW *w, int cols, int rows)
189 {
190 browser.lw = list_window_init(w, cols, rows);
191 browser.lw_state = list_window_init_state();
192 artist = NULL;
193 album = NULL;
194 }
196 static void
197 quit(void)
198 {
199 if (browser.filelist)
200 filelist_free(browser.filelist);
201 if (metalist)
202 string_list_free(metalist);
203 g_free(artist);
204 g_free(album);
205 artist = NULL;
206 album = NULL;
207 list_window_free(browser.lw);
208 list_window_free_state(browser.lw_state);
209 }
211 static void
212 open(mpd_unused screen_t *screen, mpdclient_t *c)
213 {
214 static gboolean callback_installed = FALSE;
216 if (metalist == NULL && browser.filelist == NULL)
217 update_metalist(c, NULL, NULL);
218 if (!callback_installed) {
219 mpdclient_install_browse_callback(c, browse_callback);
220 callback_installed = TRUE;
221 }
222 }
224 static void
225 resize(int cols, int rows)
226 {
227 browser.lw->cols = cols;
228 browser.lw->rows = rows;
229 }
231 static void
232 paint(mpd_unused mpdclient_t *c)
233 {
234 if (browser.filelist) {
235 list_window_paint(browser.lw, browser_lw_callback,
236 browser.filelist);
237 } else if (metalist) {
238 list_window_paint(browser.lw, artist_lw_callback, metalist);
239 } else {
240 wmove(browser.lw->w, 0, 0);
241 wclrtobot(browser.lw->w);
242 }
243 }
245 static const char *
246 get_title(char *str, size_t size)
247 {
248 char *s1 = artist ? utf8_to_locale(artist) : NULL;
249 char *s2 = album ? utf8_to_locale(album) : NULL;
251 switch(mode) {
252 case LIST_ARTISTS:
253 g_snprintf(str, size, _("Artist: [db browser - EXPERIMENTAL]"));
254 break;
255 case LIST_ALBUMS:
256 g_snprintf(str, size, _("Artist: %s"), s1);
257 break;
258 case LIST_SONGS:
259 g_snprintf(str, size, _("Artist: %s - %s"), s1, s2);
260 break;
261 }
262 g_free(s1);
263 g_free(s2);
264 return str;
265 }
267 static void
268 add_query(mpdclient_t *c, int table, char *_filter)
269 {
270 char *str;
271 mpdclient_filelist_t *addlist;
273 assert(filter != NULL);
275 str = utf8_to_locale(_filter);
276 if (table== MPD_TABLE_ALBUM)
277 screen_status_printf("Adding album %s...", str);
278 else
279 screen_status_printf("Adding %s...", str);
280 g_free(str);
282 addlist = mpdclient_filelist_search_utf8(c, TRUE, table, _filter);
283 if (addlist) {
284 mpdclient_filelist_add_all(c, addlist);
285 filelist_free(addlist);
286 }
287 }
289 static int
290 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
291 {
292 char *selected;
294 if (browser.filelist == NULL && metalist != NULL &&
295 list_window_cmd(browser.lw, metalist_length, cmd)) {
296 list_window_paint(browser.lw, artist_lw_callback, metalist);
297 wrefresh(browser.lw->w);
298 return 1;
299 }
301 switch(cmd) {
302 case CMD_PLAY:
303 switch (mode) {
304 case LIST_ARTISTS:
305 selected = (char *) g_list_nth_data(metalist,
306 browser.lw->selected);
307 update_metalist(c, g_strdup(selected), NULL);
308 list_window_push_state(browser.lw_state, browser.lw);
310 list_window_paint(browser.lw, artist_lw_callback, metalist);
311 wrefresh(browser.lw->w);
312 break;
314 case LIST_ALBUMS:
315 if (browser.lw->selected == 0) {
316 /* handle ".." */
318 update_metalist(c, NULL, NULL);
319 list_window_reset(browser.lw);
320 /* restore previous list window state */
321 list_window_pop_state(browser.lw_state, browser.lw);
322 } else if (browser.lw->selected == metalist_length - 1) {
323 /* handle "show all" */
324 update_metalist(c, g_strdup(artist), g_strdup("\0"));
325 list_window_push_state(browser.lw_state, browser.lw);
326 } else {
327 /* select album */
328 selected = g_list_nth_data(metalist,
329 browser.lw->selected);
330 update_metalist(c, g_strdup(artist), g_strdup(selected));
331 list_window_push_state(browser.lw_state, browser.lw);
332 }
334 artist_repaint();
335 break;
337 case LIST_SONGS:
338 if (browser.lw->selected == 0) {
339 /* handle ".." */
341 update_metalist(c, g_strdup(artist), NULL);
342 list_window_reset(browser.lw);
343 /* restore previous list window state */
344 list_window_pop_state(browser.lw_state,
345 browser.lw);
347 list_window_paint(browser.lw, artist_lw_callback, metalist);
348 wrefresh(browser.lw->w);
349 } else
350 browser_handle_enter(&browser, c);
351 break;
352 }
353 return 1;
356 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
358 case CMD_GO_PARENT_DIRECTORY:
359 switch (mode) {
360 case LIST_ARTISTS:
361 break;
363 case LIST_ALBUMS:
364 update_metalist(c, NULL, NULL);
365 list_window_reset(browser.lw);
366 /* restore previous list window state */
367 list_window_pop_state(browser.lw_state, browser.lw);
368 break;
370 case LIST_SONGS:
371 update_metalist(c, g_strdup(artist), NULL);
372 list_window_reset(browser.lw);
373 /* restore previous list window state */
374 list_window_pop_state(browser.lw_state, browser.lw);
375 break;
376 }
378 artist_repaint();
379 break;
381 case CMD_GO_ROOT_DIRECTORY:
382 switch (mode) {
383 case LIST_ARTISTS:
384 break;
386 case LIST_ALBUMS:
387 case LIST_SONGS:
388 update_metalist(c, NULL, NULL);
389 list_window_reset(browser.lw);
390 /* restore first list window state (pop while returning true) */
391 while(list_window_pop_state(browser.lw_state, browser.lw));
392 break;
393 }
395 artist_repaint();
396 break;
398 case CMD_SELECT:
399 switch(mode) {
400 case LIST_ARTISTS:
401 selected = g_list_nth_data(metalist,
402 browser.lw->selected);
403 if (selected == NULL)
404 return 1;
406 add_query(c, MPD_TABLE_ARTIST, selected);
407 cmd = CMD_LIST_NEXT; /* continue and select next item... */
408 break;
410 case LIST_ALBUMS:
411 if (browser.lw->selected &&
412 browser.lw->selected == metalist_length - 1)
413 add_query(c, MPD_TABLE_ARTIST, artist);
414 else if (browser.lw->selected > 0) {
415 selected = g_list_nth_data(metalist,
416 browser.lw->selected);
417 if (selected == NULL)
418 return 1;
420 add_query(c, MPD_TABLE_ALBUM, selected);
421 cmd = CMD_LIST_NEXT; /* continue and select next item... */
422 }
423 break;
425 case LIST_SONGS:
426 if (browser_handle_select(&browser, c) == 0)
427 /* continue and select next item... */
428 cmd = CMD_LIST_NEXT;
429 break;
430 }
431 break;
433 /* continue and update... */
434 case CMD_SCREEN_UPDATE:
435 update_metalist(c, g_strdup(artist), g_strdup(album));
436 screen_status_printf(_("Screen updated!"));
437 return 0;
439 case CMD_LIST_FIND:
440 case CMD_LIST_RFIND:
441 case CMD_LIST_FIND_NEXT:
442 case CMD_LIST_RFIND_NEXT:
443 if (browser.filelist)
444 screen_find(screen,
445 browser.lw, filelist_length(browser.filelist),
446 cmd, browser_lw_callback,
447 browser.filelist);
448 else if (metalist)
449 screen_find(screen,
450 browser.lw, metalist_length,
451 cmd, artist_lw_callback, metalist);
452 else
453 return 1;
455 artist_repaint();
456 return 1;
458 case CMD_MOUSE_EVENT:
459 return browser_handle_mouse_event(&browser, c);
461 default:
462 break;
463 }
465 if (browser.filelist != NULL &&
466 list_window_cmd(browser.lw, filelist_length(browser.filelist),
467 cmd)) {
468 list_window_paint(browser.lw, browser_lw_callback,
469 browser.filelist);
470 wrefresh(browser.lw->w);
471 return 1;
472 }
474 return 0;
475 }
477 const struct screen_functions screen_artist = {
478 .init = init,
479 .exit = quit,
480 .open = open,
481 .resize = resize,
482 .paint = paint,
483 .cmd = artist_cmd,
484 .get_title = get_title,
485 };