07a3f8f649f95788131293d2bd03cc48fdbd92bf
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 (screen_is_visible(&screen_artist))
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;
293 int ret;
295 if (browser.filelist == NULL && metalist != NULL &&
296 list_window_cmd(browser.lw, metalist_length, cmd)) {
297 list_window_paint(browser.lw, artist_lw_callback, metalist);
298 wrefresh(browser.lw->w);
299 return 1;
300 }
302 switch(cmd) {
303 case CMD_PLAY:
304 switch (mode) {
305 case LIST_ARTISTS:
306 selected = (char *) g_list_nth_data(metalist,
307 browser.lw->selected);
308 update_metalist(c, g_strdup(selected), NULL);
309 list_window_push_state(browser.lw_state, browser.lw);
311 list_window_paint(browser.lw, artist_lw_callback, metalist);
312 wrefresh(browser.lw->w);
313 break;
315 case LIST_ALBUMS:
316 if (browser.lw->selected == 0) {
317 /* handle ".." */
319 update_metalist(c, NULL, NULL);
320 list_window_reset(browser.lw);
321 /* restore previous list window state */
322 list_window_pop_state(browser.lw_state, browser.lw);
323 } else if (browser.lw->selected == metalist_length - 1) {
324 /* handle "show all" */
325 update_metalist(c, g_strdup(artist), g_strdup("\0"));
326 list_window_push_state(browser.lw_state, browser.lw);
327 } else {
328 /* select album */
329 selected = g_list_nth_data(metalist,
330 browser.lw->selected);
331 update_metalist(c, g_strdup(artist), g_strdup(selected));
332 list_window_push_state(browser.lw_state, browser.lw);
333 }
335 artist_repaint();
336 break;
338 case LIST_SONGS:
339 if (browser.lw->selected == 0) {
340 /* handle ".." */
342 update_metalist(c, g_strdup(artist), NULL);
343 list_window_reset(browser.lw);
344 /* restore previous list window state */
345 list_window_pop_state(browser.lw_state,
346 browser.lw);
348 list_window_paint(browser.lw, artist_lw_callback, metalist);
349 wrefresh(browser.lw->w);
350 } else
351 browser_handle_enter(&browser, c);
352 break;
353 }
354 return 1;
357 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
359 case CMD_GO_PARENT_DIRECTORY:
360 switch (mode) {
361 case LIST_ARTISTS:
362 break;
364 case LIST_ALBUMS:
365 update_metalist(c, NULL, NULL);
366 list_window_reset(browser.lw);
367 /* restore previous list window state */
368 list_window_pop_state(browser.lw_state, browser.lw);
369 break;
371 case LIST_SONGS:
372 update_metalist(c, g_strdup(artist), NULL);
373 list_window_reset(browser.lw);
374 /* restore previous list window state */
375 list_window_pop_state(browser.lw_state, browser.lw);
376 break;
377 }
379 artist_repaint();
380 break;
382 case CMD_GO_ROOT_DIRECTORY:
383 switch (mode) {
384 case LIST_ARTISTS:
385 break;
387 case LIST_ALBUMS:
388 case LIST_SONGS:
389 update_metalist(c, NULL, NULL);
390 list_window_reset(browser.lw);
391 /* restore first list window state (pop while returning true) */
392 while(list_window_pop_state(browser.lw_state, browser.lw));
393 break;
394 }
396 artist_repaint();
397 break;
399 case CMD_SELECT:
400 case CMD_ADD:
401 switch(mode) {
402 case LIST_ARTISTS:
403 selected = g_list_nth_data(metalist,
404 browser.lw->selected);
405 if (selected == NULL)
406 return 1;
408 add_query(c, MPD_TABLE_ARTIST, selected);
409 cmd = CMD_LIST_NEXT; /* continue and select next item... */
410 break;
412 case LIST_ALBUMS:
413 if (browser.lw->selected &&
414 browser.lw->selected == metalist_length - 1)
415 add_query(c, MPD_TABLE_ARTIST, artist);
416 else if (browser.lw->selected > 0) {
417 selected = g_list_nth_data(metalist,
418 browser.lw->selected);
419 if (selected == NULL)
420 return 1;
422 add_query(c, MPD_TABLE_ALBUM, selected);
423 cmd = CMD_LIST_NEXT; /* continue and select next item... */
424 }
425 break;
427 case LIST_SONGS:
428 ret = cmd == CMD_SELECT
429 ? browser_handle_select(&browser, c)
430 : browser_handle_add(&browser, c);
431 if (ret == 0)
432 /* continue and select next item... */
433 cmd = CMD_LIST_NEXT;
434 break;
435 }
436 break;
438 /* continue and update... */
439 case CMD_SCREEN_UPDATE:
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 (browser.filelist)
449 screen_find(screen,
450 browser.lw, filelist_length(browser.filelist),
451 cmd, browser_lw_callback,
452 browser.filelist);
453 else if (metalist)
454 screen_find(screen,
455 browser.lw, metalist_length,
456 cmd, artist_lw_callback, metalist);
457 else
458 return 1;
460 artist_repaint();
461 return 1;
463 case CMD_MOUSE_EVENT:
464 return browser_handle_mouse_event(&browser, c);
466 default:
467 break;
468 }
470 if (browser.filelist != NULL &&
471 list_window_cmd(browser.lw, filelist_length(browser.filelist),
472 cmd)) {
473 list_window_paint(browser.lw, browser_lw_callback,
474 browser.filelist);
475 wrefresh(browser.lw->w);
476 return 1;
477 }
479 return 0;
480 }
482 const struct screen_functions screen_artist = {
483 .init = init,
484 .exit = quit,
485 .open = open,
486 .resize = resize,
487 .paint = paint,
488 .cmd = artist_cmd,
489 .get_title = get_title,
490 };