1 /*
2 * $Id$
3 *
4 * (c) 2005 by Kalle Wallin <kaw@linux.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <ncurses.h>
27 #include "config.h"
28 #ifndef DISABLE_ARTIST_SCREEN
29 #include "ncmpc.h"
30 #include "options.h"
31 #include "support.h"
32 #include "mpdclient.h"
33 #include "utils.h"
34 #include "strfsong.h"
35 #include "command.h"
36 #include "screen.h"
37 #include "screen_utils.h"
38 #include "screen_browse.h"
40 #define BUFSIZE 1024
42 typedef enum { LIST_ARTISTS, LIST_ALBUMS, LIST_SONGS } artist_mode_t;
44 static artist_mode_t mode = LIST_ARTISTS;
45 static char *artist = NULL;
46 static char *album = NULL;
47 static list_window_t *lw = NULL;
48 static mpdclient_filelist_t *filelist = NULL;
49 static int metalist_length = 0;
50 static GList *metalist = NULL;
51 static list_window_state_t *lw_state = NULL;
53 static gint
54 compare_utf8(gconstpointer s1, gconstpointer s2)
55 {
56 char *key1, *key2;
57 int n;
59 key1 = g_utf8_collate_key(s1,-1);
60 key2 = g_utf8_collate_key(s2,-1);
61 n = strcmp(key1,key2);
62 g_free(key1);
63 g_free(key2);
64 return n;
65 }
67 /* list_window callback */
68 static char *
69 artist_lw_callback(int index, int *highlight, void *data)
70 {
71 static char buf[BUFSIZE];
72 char *str, *str_utf8;
74 *highlight = 0;
75 if( (str_utf8=(char *) g_list_nth_data(metalist,index))==NULL )
76 return NULL;
78 str = utf8_to_locale(str_utf8);
79 g_snprintf(buf, BUFSIZE, "[%s]", str);
80 g_free(str);
82 return buf;
83 }
85 /* the playlist have been updated -> fix highlights */
86 static void
87 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
88 {
89 if( filelist==NULL )
90 return;
91 D("screen_artist.c> playlist_callback() [%d]\n", event);
92 switch(event)
93 {
94 case PLAYLIST_EVENT_CLEAR:
95 clear_highlights(filelist);
96 break;
97 default:
98 sync_highlights(c, filelist);
99 break;
100 }
101 }
103 /* fetch artists/albums/songs from mpd */
104 static void
105 update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
106 {
107 g_free(artist);
108 g_free(album);
109 artist = NULL;
110 album = NULL;
111 if( metalist )
112 metalist = string_list_free(metalist);
113 if (filelist ) {
114 mpdclient_remove_playlist_callback(c, playlist_changed_callback);
115 filelist = mpdclient_filelist_free(filelist);
116 }
117 if( m_album ) /* retreive songs... */
118 {
119 artist = m_artist;
120 album = m_album;
121 if( album[0] == 0 )
122 {
123 album = g_strdup(_("All tracks"));
124 filelist = mpdclient_filelist_search_utf8(c,
125 TRUE,
126 MPD_TABLE_ARTIST,
127 artist);
128 }
129 else
130 filelist = mpdclient_filelist_search_utf8(c,
131 TRUE,
132 MPD_TABLE_ALBUM,
133 album);
134 /* add a dummy entry for ".." */
135 filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
136 entry->entity = NULL;
137 filelist->list = g_list_insert(filelist->list, entry, 0);
138 filelist->length++;
139 /* install playlist callback and fix highlights */
140 sync_highlights(c, filelist);
141 mpdclient_install_playlist_callback(c, playlist_changed_callback);
142 mode = LIST_SONGS;
143 }
144 else if( m_artist ) /* retreive albums... */
145 {
146 artist = m_artist;
147 metalist = mpdclient_get_albums_utf8(c, m_artist);
148 /* sort list */
149 metalist = g_list_sort(metalist, compare_utf8);
150 /* add a dummy entry for ".." */
151 metalist = g_list_insert(metalist, g_strdup(".."), 0);
152 /* add a dummy entry for all songs */
153 metalist = g_list_insert(metalist, g_strdup(_("All tracks")), -1);
154 mode = LIST_ALBUMS;
155 }
156 else /* retreive artists... */
157 {
158 metalist = mpdclient_get_artists_utf8(c);
159 /* sort list */
160 metalist = g_list_sort(metalist, compare_utf8);
161 mode = LIST_ARTISTS;
162 }
163 metalist_length = g_list_length(metalist);
164 lw->clear = TRUE;
165 }
167 /* db updated */
168 static void
169 browse_callback(mpdclient_t *c, int event, gpointer data)
170 {
171 switch(event)
172 {
173 case BROWSE_DB_UPDATED:
174 D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
175 lw->clear = 1;
176 lw->repaint = 1;
177 update_metalist(c, g_strdup(artist), g_strdup(album));
178 break;
179 default:
180 break;
181 }
182 }
184 static void
185 init(WINDOW *w, int cols, int rows)
186 {
187 lw = list_window_init(w, cols, rows);
188 lw_state = list_window_init_state();
189 artist = NULL;
190 album = NULL;
191 }
193 static void
194 quit(void)
195 {
196 if( filelist )
197 filelist = mpdclient_filelist_free(filelist);
198 if( metalist )
199 metalist = string_list_free(metalist);
200 g_free(artist);
201 g_free(album);
202 artist = NULL;
203 album = NULL;
204 lw = list_window_free(lw);
205 lw_state = list_window_free_state(lw_state);
206 }
208 static void
209 open(screen_t *screen, mpdclient_t *c)
210 {
211 static gboolean callback_installed = FALSE;
213 if( metalist==NULL && filelist ==NULL)
214 update_metalist(c, NULL, NULL);
215 if( !callback_installed )
216 {
217 mpdclient_install_browse_callback(c, browse_callback);
218 callback_installed = TRUE;
219 }
220 }
222 static void
223 resize(int cols, int rows)
224 {
225 lw->cols = cols;
226 lw->rows = rows;
227 }
229 static void
230 close(void)
231 {
232 }
234 static void
235 paint(screen_t *screen, mpdclient_t *c)
236 {
237 lw->clear = 1;
239 if( filelist )
240 {
241 list_window_paint(lw, browse_lw_callback, (void *) filelist);
242 filelist->updated = FALSE;
243 }
244 else if( metalist )
245 {
246 list_window_paint(lw, artist_lw_callback, (void *) metalist);
247 }
248 else
249 {
250 wmove(lw->w, 0, 0);
251 wclrtobot(lw->w);
252 }
253 wnoutrefresh(lw->w);
254 }
256 static void
257 update(screen_t *screen, mpdclient_t *c)
258 {
259 if( filelist && !filelist->updated )
260 {
261 list_window_paint(lw, browse_lw_callback, (void *) filelist);
262 }
263 else if( metalist )
264 {
265 list_window_paint(lw, artist_lw_callback, (void *) metalist);
266 }
267 else
268 {
269 paint(screen, c);
270 }
271 wnoutrefresh(lw->w);
272 }
274 static char *
275 get_title(char *str, size_t size)
276 {
277 char *s1 = artist ? utf8_to_locale(artist) : NULL;
278 char *s2 = album ? utf8_to_locale(album) : NULL;
280 switch(mode)
281 {
282 case LIST_ARTISTS:
283 g_snprintf(str, size, _("Artist: [db browser - EXPERIMENTAL]"));
284 break;
285 case LIST_ALBUMS:
286 g_snprintf(str, size, _("Artist: %s"), s1);
287 break;
288 case LIST_SONGS:
289 g_snprintf(str, size, _("Artist: %s - %s"), s1, s2);
290 break;
291 }
292 g_free(s1);
293 g_free(s2);
294 return str;
295 }
297 static list_window_t *
298 get_filelist_window()
299 {
300 return lw;
301 }
303 static void
304 add_query(mpdclient_t *c, int table, char *filter)
305 {
306 char *str;
307 mpdclient_filelist_t *addlist;
309 str = utf8_to_locale(filter);
310 if( table== MPD_TABLE_ALBUM )
311 screen_status_printf("Adding album %s...", str);
312 else
313 screen_status_printf("Adding %s...", str);
314 g_free(str);
315 addlist = mpdclient_filelist_search_utf8(c, TRUE, table, filter);
316 if( addlist )
317 {
318 mpdclient_filelist_add_all(c, addlist);
319 addlist = mpdclient_filelist_free(addlist);
320 }
321 }
323 static int
324 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
325 {
326 char *selected;
328 switch(cmd)
329 {
330 case CMD_PLAY:
331 switch(mode)
332 {
333 case LIST_ARTISTS:
334 selected = (char *) g_list_nth_data(metalist, lw->selected);
335 update_metalist(c, g_strdup(selected), NULL);
336 list_window_push_state(lw_state,lw);
337 break;
338 case LIST_ALBUMS:
339 if( lw->selected == 0 ) /* handle ".." */
340 {
341 update_metalist(c, NULL, NULL);
342 list_window_reset(lw);
343 /* restore previous list window state */
344 list_window_pop_state(lw_state,lw);
345 }
346 else if( lw->selected == metalist_length-1) /* handle "show all" */
347 {
348 update_metalist(c, g_strdup(artist), g_strdup("\0"));
349 list_window_push_state(lw_state,lw);
350 }
351 else /* select album */
352 {
353 selected = (char *) g_list_nth_data(metalist, lw->selected);
354 update_metalist(c, g_strdup(artist), g_strdup(selected));
355 list_window_push_state(lw_state,lw);
356 }
357 break;
358 case LIST_SONGS:
359 if( lw->selected==0 ) /* handle ".." */
360 {
361 update_metalist(c, g_strdup(artist), NULL);
362 list_window_reset(lw);
363 /* restore previous list window state */
364 list_window_pop_state(lw_state,lw);
365 }
366 else
367 browse_handle_enter(screen, c, lw, filelist);
368 break;
369 }
370 return 1;
373 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
375 case CMD_GO_PARENT_DIRECTORY:
376 switch(mode)
377 {
378 case LIST_ALBUMS:
379 update_metalist(c, NULL, NULL);
380 list_window_reset(lw);
381 /* restore previous list window state */
382 list_window_pop_state(lw_state,lw);
383 break;
384 case LIST_SONGS:
385 update_metalist(c, g_strdup(artist), NULL);
386 list_window_reset(lw);
387 /* restore previous list window state */
388 list_window_pop_state(lw_state,lw);
389 break;
390 }
391 break;
393 case CMD_GO_ROOT_DIRECTORY:
394 switch(mode)
395 {
396 case LIST_ALBUMS:
397 case LIST_SONGS:
398 update_metalist(c, NULL, NULL);
399 list_window_reset(lw);
400 /* restore first list window state (pop while returning true) */
401 while(list_window_pop_state(lw_state,lw));
402 break;
403 }
404 break;
406 case CMD_SELECT:
407 switch(mode)
408 {
409 case LIST_ARTISTS:
410 selected = (char *) g_list_nth_data(metalist, lw->selected);
411 add_query(c, MPD_TABLE_ARTIST, selected);
412 cmd = CMD_LIST_NEXT; /* continue and select next item... */
413 break;
414 case LIST_ALBUMS:
415 if( lw->selected && lw->selected == metalist_length-1)
416 {
417 add_query(c, MPD_TABLE_ARTIST, artist);
418 }
419 else if( lw->selected > 0 )
420 {
421 selected = (char *) g_list_nth_data(metalist, lw->selected);
422 add_query(c, MPD_TABLE_ALBUM, selected);
423 cmd = CMD_LIST_NEXT; /* continue and select next item... */
424 }
425 break;
426 case LIST_SONGS:
427 if( browse_handle_select(screen, c, lw, filelist) == 0 )
428 {
429 cmd = CMD_LIST_NEXT; /* continue and select next item... */
430 }
431 break;
432 }
433 break;
435 /* continue and update... */
436 case CMD_SCREEN_UPDATE:
437 screen->painted = 0;
438 lw->clear = 1;
439 lw->repaint = 1;
440 update_metalist(c, g_strdup(artist), g_strdup(album));
441 screen_status_printf(_("Screen updated!"));
442 return 0;
444 case CMD_LIST_FIND:
445 case CMD_LIST_RFIND:
446 case CMD_LIST_FIND_NEXT:
447 case CMD_LIST_RFIND_NEXT:
448 if( filelist )
449 return screen_find(screen, c,
450 lw, filelist->length,
451 cmd, browse_lw_callback, (void *) filelist);
452 else if ( metalist )
453 return screen_find(screen, c,
454 lw, metalist_length,
455 cmd, artist_lw_callback, (void *) metalist);
456 else
457 return 1;
459 case CMD_MOUSE_EVENT:
460 return browse_handle_mouse_event(screen,c,lw,filelist);
462 default:
463 break;
464 }
466 if( filelist )
467 return list_window_cmd(lw, filelist->length, cmd);
468 else if( metalist )
469 return list_window_cmd(lw, metalist_length, cmd);
472 return 0;
473 }
475 screen_functions_t *
476 get_screen_artist(void)
477 {
478 static screen_functions_t functions;
480 memset(&functions, 0, sizeof(screen_functions_t));
481 functions.init = init;
482 functions.exit = quit;
483 functions.open = open;
484 functions.close = close;
485 functions.resize = resize;
486 functions.paint = paint;
487 functions.update = update;
488 functions.cmd = artist_cmd;
489 functions.get_lw = get_filelist_window;
490 functions.get_title = get_title;
492 return &functions;
493 }
496 #endif /* ENABLE_ARTIST_SCREEN */