6857b66adb712e2cbe94eaa5fcdde9a614dff59a
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 "config.h"
21 #ifndef DISABLE_ARTIST_SCREEN
22 #include "ncmpc.h"
23 #include "options.h"
24 #include "support.h"
25 #include "mpdclient.h"
26 #include "utils.h"
27 #include "strfsong.h"
28 #include "command.h"
29 #include "screen.h"
30 #include "screen_utils.h"
31 #include "screen_browser.h"
32 #include "gcc.h"
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <glib.h>
38 #include <ncurses.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 unsigned metalist_length = 0;
48 static GList *metalist = NULL;
50 static struct screen_browser browser;
52 static gint
53 compare_utf8(gconstpointer s1, gconstpointer s2)
54 {
55 char *key1, *key2;
56 int n;
58 key1 = g_utf8_collate_key(s1,-1);
59 key2 = g_utf8_collate_key(s2,-1);
60 n = strcmp(key1,key2);
61 g_free(key1);
62 g_free(key2);
63 return n;
64 }
66 /* list_window callback */
67 static const char *
68 artist_lw_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data)
69 {
70 static char buf[BUFSIZE];
71 char *str, *str_utf8;
73 if ((str_utf8 = (char *)g_list_nth_data(metalist, idx)) == NULL)
74 return NULL;
76 str = utf8_to_locale(str_utf8);
77 g_snprintf(buf, BUFSIZE, "[%s]", str);
78 g_free(str);
80 return buf;
81 }
83 /* the playlist have been updated -> fix highlights */
84 static void
85 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
86 {
87 browser_playlist_changed(&browser, c, event, data);
88 }
90 /* fetch artists/albums/songs from mpd */
91 static void
92 update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
93 {
94 g_free(artist);
95 g_free(album);
96 artist = NULL;
97 album = NULL;
99 if (metalist)
100 metalist = string_list_free(metalist);
101 if (browser.filelist) {
102 mpdclient_remove_playlist_callback(c, playlist_changed_callback);
103 filelist_free(browser.filelist);
104 browser.filelist = NULL;
105 }
107 if (m_album) {
108 /* retreive songs... */
109 artist = m_artist;
110 album = m_album;
111 if (album[0] == 0) {
112 album = g_strdup(_("All tracks"));
113 browser.filelist =
114 mpdclient_filelist_search_utf8(c, TRUE,
115 MPD_TABLE_ARTIST,
116 artist);
117 } else
118 browser.filelist =
119 mpdclient_filelist_search_utf8(c, TRUE,
120 MPD_TABLE_ALBUM,
121 album);
122 if (browser.filelist == NULL)
123 browser.filelist = filelist_new(NULL);
125 /* add a dummy entry for ".." */
126 filelist_prepend(browser.filelist, NULL);
128 /* install playlist callback and fix highlights */
129 sync_highlights(c, browser.filelist);
130 mpdclient_install_playlist_callback(c, playlist_changed_callback);
131 mode = LIST_SONGS;
132 } else if (m_artist) {
133 /* retreive albums... */
135 artist = m_artist;
136 metalist = mpdclient_get_albums_utf8(c, m_artist);
137 /* sort list */
138 metalist = g_list_sort(metalist, compare_utf8);
139 /* add a dummy entry for ".." */
140 metalist = g_list_insert(metalist, g_strdup(".."), 0);
141 /* add a dummy entry for all songs */
142 metalist = g_list_insert(metalist, g_strdup(_("All tracks")), -1);
143 mode = LIST_ALBUMS;
144 } else {
145 /* retreive artists... */
147 metalist = mpdclient_get_artists_utf8(c);
148 /* sort list */
149 metalist = g_list_sort(metalist, compare_utf8);
150 mode = LIST_ARTISTS;
151 }
152 metalist_length = g_list_length(metalist);
153 }
155 /* db updated */
156 static void
157 browse_callback(mpdclient_t *c, int event, mpd_unused gpointer data)
158 {
159 switch(event) {
160 case BROWSE_DB_UPDATED:
161 D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
162 update_metalist(c, g_strdup(artist), g_strdup(album));
163 break;
164 default:
165 break;
166 }
167 }
169 static void
170 init(WINDOW *w, int cols, int rows)
171 {
172 browser.lw = list_window_init(w, cols, rows);
173 browser.lw_state = list_window_init_state();
174 artist = NULL;
175 album = NULL;
176 }
178 static void
179 quit(void)
180 {
181 if (browser.filelist)
182 filelist_free(browser.filelist);
183 if (metalist)
184 string_list_free(metalist);
185 g_free(artist);
186 g_free(album);
187 artist = NULL;
188 album = NULL;
189 list_window_free(browser.lw);
190 list_window_free_state(browser.lw_state);
191 }
193 static void
194 open(mpd_unused screen_t *screen, mpdclient_t *c)
195 {
196 static gboolean callback_installed = FALSE;
198 if (metalist == NULL && browser.filelist == NULL)
199 update_metalist(c, NULL, NULL);
200 if (!callback_installed) {
201 mpdclient_install_browse_callback(c, browse_callback);
202 callback_installed = TRUE;
203 }
204 }
206 static void
207 resize(int cols, int rows)
208 {
209 browser.lw->cols = cols;
210 browser.lw->rows = rows;
211 }
213 static void
214 paint(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c)
215 {
216 if (browser.filelist) {
217 list_window_paint(browser.lw, browser_lw_callback,
218 browser.filelist);
219 browser.filelist->updated = FALSE;
220 } else if (metalist) {
221 list_window_paint(browser.lw, artist_lw_callback, metalist);
222 } else {
223 wmove(browser.lw->w, 0, 0);
224 wclrtobot(browser.lw->w);
225 }
226 }
228 static void
229 update(screen_t *screen, mpdclient_t *c)
230 {
231 if (browser.filelist && !browser.filelist->updated)
232 list_window_paint(browser.lw, browser_lw_callback,
233 browser.filelist);
234 else if (metalist)
235 list_window_paint(browser.lw, artist_lw_callback, metalist);
236 else
237 paint(screen, c);
238 wnoutrefresh(browser.lw->w);
239 }
241 static const char *
242 get_title(char *str, size_t size)
243 {
244 char *s1 = artist ? utf8_to_locale(artist) : NULL;
245 char *s2 = album ? utf8_to_locale(album) : NULL;
247 switch(mode) {
248 case LIST_ARTISTS:
249 g_snprintf(str, size, _("Artist: [db browser - EXPERIMENTAL]"));
250 break;
251 case LIST_ALBUMS:
252 g_snprintf(str, size, _("Artist: %s"), s1);
253 break;
254 case LIST_SONGS:
255 g_snprintf(str, size, _("Artist: %s - %s"), s1, s2);
256 break;
257 }
258 g_free(s1);
259 g_free(s2);
260 return str;
261 }
263 static void
264 add_query(mpdclient_t *c, int table, char *_filter)
265 {
266 char *str;
267 mpdclient_filelist_t *addlist;
269 assert(filter != NULL);
271 str = utf8_to_locale(_filter);
272 if (table== MPD_TABLE_ALBUM)
273 screen_status_printf("Adding album %s...", str);
274 else
275 screen_status_printf("Adding %s...", str);
276 g_free(str);
278 addlist = mpdclient_filelist_search_utf8(c, TRUE, table, _filter);
279 if (addlist) {
280 mpdclient_filelist_add_all(c, addlist);
281 filelist_free(addlist);
282 }
283 }
285 static int
286 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
287 {
288 char *selected;
290 switch(cmd) {
291 case CMD_PLAY:
292 switch (mode) {
293 case LIST_ARTISTS:
294 selected = (char *) g_list_nth_data(metalist,
295 browser.lw->selected);
296 update_metalist(c, g_strdup(selected), NULL);
297 list_window_push_state(browser.lw_state, browser.lw);
298 break;
300 case LIST_ALBUMS:
301 if (browser.lw->selected == 0) {
302 /* handle ".." */
304 update_metalist(c, NULL, NULL);
305 list_window_reset(browser.lw);
306 /* restore previous list window state */
307 list_window_pop_state(browser.lw_state, browser.lw);
308 } else if (browser.lw->selected == metalist_length - 1) {
309 /* handle "show all" */
310 update_metalist(c, g_strdup(artist), g_strdup("\0"));
311 list_window_push_state(browser.lw_state, browser.lw);
312 } else {
313 /* select album */
314 selected = g_list_nth_data(metalist,
315 browser.lw->selected);
316 update_metalist(c, g_strdup(artist), g_strdup(selected));
317 list_window_push_state(browser.lw_state, browser.lw);
318 }
319 break;
321 case LIST_SONGS:
322 if (browser.lw->selected == 0) {
323 /* handle ".." */
325 update_metalist(c, g_strdup(artist), NULL);
326 list_window_reset(browser.lw);
327 /* restore previous list window state */
328 list_window_pop_state(browser.lw_state,
329 browser.lw);
330 } else
331 browser_handle_enter(&browser, c);
332 break;
333 }
334 return 1;
337 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
339 case CMD_GO_PARENT_DIRECTORY:
340 switch (mode) {
341 case LIST_ARTISTS:
342 break;
344 case LIST_ALBUMS:
345 update_metalist(c, NULL, NULL);
346 list_window_reset(browser.lw);
347 /* restore previous list window state */
348 list_window_pop_state(browser.lw_state, browser.lw);
349 break;
351 case LIST_SONGS:
352 update_metalist(c, g_strdup(artist), NULL);
353 list_window_reset(browser.lw);
354 /* restore previous list window state */
355 list_window_pop_state(browser.lw_state, browser.lw);
356 break;
357 }
358 break;
360 case CMD_GO_ROOT_DIRECTORY:
361 switch (mode) {
362 case LIST_ARTISTS:
363 break;
365 case LIST_ALBUMS:
366 case LIST_SONGS:
367 update_metalist(c, NULL, NULL);
368 list_window_reset(browser.lw);
369 /* restore first list window state (pop while returning true) */
370 while(list_window_pop_state(browser.lw_state, browser.lw));
371 break;
372 }
373 break;
375 case CMD_SELECT:
376 switch(mode) {
377 case LIST_ARTISTS:
378 selected = g_list_nth_data(metalist,
379 browser.lw->selected);
380 if (selected == NULL)
381 return 1;
383 add_query(c, MPD_TABLE_ARTIST, selected);
384 cmd = CMD_LIST_NEXT; /* continue and select next item... */
385 break;
387 case LIST_ALBUMS:
388 if (browser.lw->selected &&
389 browser.lw->selected == metalist_length - 1)
390 add_query(c, MPD_TABLE_ARTIST, artist);
391 else if (browser.lw->selected > 0) {
392 selected = g_list_nth_data(metalist,
393 browser.lw->selected);
394 if (selected == NULL)
395 return 1;
397 add_query(c, MPD_TABLE_ALBUM, selected);
398 cmd = CMD_LIST_NEXT; /* continue and select next item... */
399 }
400 break;
402 case LIST_SONGS:
403 if (browser_handle_select(&browser, c) == 0)
404 /* continue and select next item... */
405 cmd = CMD_LIST_NEXT;
406 break;
407 }
408 break;
410 /* continue and update... */
411 case CMD_SCREEN_UPDATE:
412 update_metalist(c, g_strdup(artist), g_strdup(album));
413 screen_status_printf(_("Screen updated!"));
414 return 0;
416 case CMD_LIST_FIND:
417 case CMD_LIST_RFIND:
418 case CMD_LIST_FIND_NEXT:
419 case CMD_LIST_RFIND_NEXT:
420 if (browser.filelist)
421 return screen_find(screen,
422 browser.lw, filelist_length(browser.filelist),
423 cmd, browser_lw_callback,
424 browser.filelist);
425 else if (metalist)
426 return screen_find(screen,
427 browser.lw, metalist_length,
428 cmd, artist_lw_callback, metalist);
429 else
430 return 1;
432 case CMD_MOUSE_EVENT:
433 return browser_handle_mouse_event(&browser, c);
435 default:
436 break;
437 }
439 if (browser.filelist)
440 return list_window_cmd(browser.lw, filelist_length(browser.filelist), cmd);
441 else if (metalist)
442 return list_window_cmd(browser.lw, metalist_length, cmd);
444 return 0;
445 }
447 const struct screen_functions screen_artist = {
448 .init = init,
449 .exit = quit,
450 .open = open,
451 .resize = resize,
452 .paint = paint,
453 .update = update,
454 .cmd = artist_cmd,
455 .get_title = get_title,
456 };
458 #endif /* ENABLE_ARTIST_SCREEN */