Code

d8894534042b1d01bf81101ab4d992bbc3ac5fcb
[ncmpc.git] / src / screen_artist.c
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 GPtrArray *metalist = NULL;
46 static struct screen_browser browser;
48 static gint
49 compare_utf8(gconstpointer s1, gconstpointer s2)
50 {
51         char *key1, *key2;
52         int n;
54         key1 = g_utf8_collate_key(s1,-1);
55         key2 = g_utf8_collate_key(s2,-1);
56         n = strcmp(key1,key2);
57         g_free(key1);
58         g_free(key2);
59         return n;
60 }
62 /* list_window callback */
63 static const char *
64 artist_lw_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data)
65 {
66         static char buf[BUFSIZE];
67         char *str, *str_utf8;
69         if (mode == LIST_ALBUMS) {
70                 if (idx == 0)
71                         return "[..]";
72                 else if (idx == metalist->len + 1) {
73                         str = utf8_to_locale(_("All tracks"));
74                         g_snprintf(buf, BUFSIZE, "[%s]", str);
75                         g_free(str);
76                         return buf;
77                 }
79                 --idx;
80         }
82         if (idx >= metalist->len)
83                 return NULL;
85         str_utf8 = g_ptr_array_index(metalist, idx);
86         assert(str_utf8 != NULL);
88         str = utf8_to_locale(str_utf8);
89         g_snprintf(buf, BUFSIZE, "[%s]", str);
90         g_free(str);
92         return buf;
93 }
95 static void
96 paint(mpdclient_t *c);
98 static void
99 artist_repaint(void)
101         paint(NULL);
102         wrefresh(browser.lw->w);
105 static void
106 artist_repaint_if_active(void)
108         if (screen_is_visible(&screen_artist))
109                 artist_repaint();
112 /* the playlist have been updated -> fix highlights */
113 static void
114 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
116         browser_playlist_changed(&browser, c, event, data);
118         artist_repaint_if_active();
121 static GPtrArray *
122 g_list_to_ptr_array(GList *in)
124         GPtrArray *out = g_ptr_array_sized_new(g_list_length(in));
125         GList *head = in;
127         while (in != NULL) {
128                 g_ptr_array_add(out, in->data);
129                 in = g_list_next(in);
130         }
132         g_list_free(head);
133         return out;
136 static void
137 string_array_free(GPtrArray *array)
139         unsigned i;
141         for (i = 0; i < array->len; ++i) {
142                 char *value = g_ptr_array_index(array, i);
143                 free(value);
144         }
146         g_ptr_array_free(array, TRUE);
149 /* fetch artists/albums/songs from mpd */
150 static void
151 update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
153         g_free(artist);
154         g_free(album);
155         artist = NULL;
156         album = NULL;
158         if (metalist != NULL) {
159                 string_array_free(metalist);
160                 metalist = NULL;
161         }
163         if (browser.filelist) {
164                 mpdclient_remove_playlist_callback(c, playlist_changed_callback);
165                 filelist_free(browser.filelist);
166                 browser.filelist = NULL;
167         }
169         if (m_album) {
170                 /* retreive songs... */
171                 artist = m_artist;
172                 album = m_album;
173                 if (album[0] == 0) {
174                         album = g_strdup(_("All tracks"));
175                         browser.filelist =
176                                 mpdclient_filelist_search_utf8(c, TRUE,
177                                                                MPD_TABLE_ARTIST,
178                                                                artist);
179                 } else
180                         browser.filelist =
181                                 mpdclient_filelist_search_utf8(c, TRUE,
182                                                                MPD_TABLE_ALBUM,
183                                                                album);
184                 if (browser.filelist == NULL)
185                         browser.filelist = filelist_new(NULL);
187                 /* add a dummy entry for ".." */
188                 filelist_prepend(browser.filelist, NULL);
190                 /* install playlist callback and fix highlights */
191                 sync_highlights(c, browser.filelist);
192                 mpdclient_install_playlist_callback(c, playlist_changed_callback);
193                 mode = LIST_SONGS;
194         } else if (m_artist) {
195                 /* retreive albums... */
196                 GList *list;
198                 artist = m_artist;
199                 list = mpdclient_get_albums_utf8(c, m_artist);
200                 /* sort list */
201                 list = g_list_sort(list, compare_utf8);
203                 metalist = g_list_to_ptr_array(list);
204                 mode = LIST_ALBUMS;
205         } else {
206                 /* retreive artists... */
207                 GList *list;
209                 list = mpdclient_get_artists_utf8(c);
210                 /* sort list */
211                 list = g_list_sort(list, compare_utf8);
213                 metalist = g_list_to_ptr_array(list);
214                 mode = LIST_ARTISTS;
215         }
218 /* db updated */
219 static void
220 browse_callback(mpdclient_t *c, int event, mpd_unused gpointer data)
222         switch(event) {
223         case BROWSE_DB_UPDATED:
224                 D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
225                 update_metalist(c, g_strdup(artist), g_strdup(album));
226                 break;
227         default:
228                 break;
229         }
231         artist_repaint_if_active();
234 static void
235 init(WINDOW *w, int cols, int rows)
237         browser.lw = list_window_init(w, cols, rows);
238         browser.lw_state = list_window_init_state();
239         artist = NULL;
240         album = NULL;
243 static void
244 quit(void)
246         if (browser.filelist)
247                 filelist_free(browser.filelist);
248         if (metalist)
249                 string_array_free(metalist);
250         g_free(artist);
251         g_free(album);
252         artist = NULL;
253         album = NULL;
254         list_window_free(browser.lw);
255         list_window_free_state(browser.lw_state);
258 static void
259 open(mpd_unused screen_t *screen, mpdclient_t *c)
261         static gboolean callback_installed = FALSE;
263         if (metalist == NULL && browser.filelist == NULL)
264                 update_metalist(c, NULL, NULL);
265         if (!callback_installed) {
266                 mpdclient_install_browse_callback(c, browse_callback);
267                 callback_installed = TRUE;
268         }
271 static void
272 resize(int cols, int rows)
274         browser.lw->cols = cols;
275         browser.lw->rows = rows;
278 static void
279 paint(mpd_unused mpdclient_t *c)
281         if (browser.filelist) {
282                 list_window_paint(browser.lw, browser_lw_callback,
283                                   browser.filelist);
284         } else if (metalist) {
285                 list_window_paint(browser.lw, artist_lw_callback, metalist);
286         } else {
287                 wmove(browser.lw->w, 0, 0);
288                 wclrtobot(browser.lw->w);
289         }
292 static const char *
293 get_title(char *str, size_t size)
295         char *s1 = artist ? utf8_to_locale(artist) : NULL;
296         char *s2 = album ? utf8_to_locale(album) : NULL;
298         switch(mode) {
299         case LIST_ARTISTS:
300                 g_snprintf(str, size,  _("Artist: [db browser - EXPERIMENTAL]"));
301                 break;
302         case LIST_ALBUMS:
303                 g_snprintf(str, size,  _("Artist: %s"), s1);
304                 break;
305         case LIST_SONGS:
306                 g_snprintf(str, size,  _("Artist: %s - %s"), s1, s2);
307                 break;
308         }
309         g_free(s1);
310         g_free(s2);
311         return str;
314 static void
315 add_query(mpdclient_t *c, int table, char *_filter)
317         char *str;
318         mpdclient_filelist_t *addlist;
320         assert(filter != NULL);
322         str = utf8_to_locale(_filter);
323         if (table== MPD_TABLE_ALBUM)
324                 screen_status_printf("Adding album %s...", str);
325         else
326                 screen_status_printf("Adding %s...", str);
327         g_free(str);
329         addlist = mpdclient_filelist_search_utf8(c, TRUE, table, _filter);
330         if (addlist) {
331                 mpdclient_filelist_add_all(c, addlist);
332                 filelist_free(addlist);
333         }
336 static unsigned
337 metalist_length(void)
339         assert(metalist != NULL);
341         return mode == LIST_ALBUMS
342                 ? metalist->len + 2
343                 : metalist->len;
346 static int
347 artist_lw_cmd(command_t cmd)
349         switch (mode) {
350         case LIST_ARTISTS:
351         case LIST_ALBUMS:
352                 return list_window_cmd(browser.lw, metalist_length(), cmd);
354         case LIST_SONGS:
355                 return list_window_cmd(browser.lw,
356                                        filelist_length(browser.filelist),
357                                        cmd);
358         }
360         assert(0);
361         return 0;
364 static int
365 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
367         char *selected;
368         int ret;
370         if (artist_lw_cmd(cmd)) {
371                 artist_repaint();
372                 wrefresh(browser.lw->w);
373                 return 1;
374         }
376         switch(cmd) {
377         case CMD_PLAY:
378                 switch (mode) {
379                 case LIST_ARTISTS:
380                         selected = g_ptr_array_index(metalist,
381                                                      browser.lw->selected);
382                         update_metalist(c, g_strdup(selected), NULL);
383                         list_window_push_state(browser.lw_state, browser.lw);
385                         list_window_paint(browser.lw, artist_lw_callback, metalist);
386                         wrefresh(browser.lw->w);
387                         break;
389                 case LIST_ALBUMS:
390                         if (browser.lw->selected == 0) {
391                                 /* handle ".." */
393                                 update_metalist(c, NULL, NULL);
394                                 list_window_reset(browser.lw);
395                                 /* restore previous list window state */
396                                 list_window_pop_state(browser.lw_state, browser.lw);
397                         } else if (browser.lw->selected == metalist->len + 1) {
398                                 /* handle "show all" */
399                                 update_metalist(c, g_strdup(artist), g_strdup("\0"));
400                                 list_window_push_state(browser.lw_state, browser.lw);
401                         } else {
402                                 /* select album */
403                                 selected = g_ptr_array_index(metalist,
404                                                              browser.lw->selected - 1);
405                                 update_metalist(c, g_strdup(artist), g_strdup(selected));
406                                 list_window_push_state(browser.lw_state, browser.lw);
407                         }
409                         artist_repaint();
410                         break;
412                 case LIST_SONGS:
413                         if (browser.lw->selected == 0) {
414                                 /* handle ".." */
416                                 update_metalist(c, g_strdup(artist), NULL);
417                                 list_window_reset(browser.lw);
418                                 /* restore previous list window state */
419                                 list_window_pop_state(browser.lw_state,
420                                                       browser.lw);
422                                 list_window_paint(browser.lw, artist_lw_callback, metalist);
423                                 wrefresh(browser.lw->w);
424                         } else
425                                 browser_handle_enter(&browser, c);
426                         break;
427                 }
428                 return 1;
431                 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
433         case CMD_GO_PARENT_DIRECTORY:
434                 switch (mode) {
435                 case LIST_ARTISTS:
436                         break;
438                 case LIST_ALBUMS:
439                         update_metalist(c, NULL, NULL);
440                         list_window_reset(browser.lw);
441                         /* restore previous list window state */
442                         list_window_pop_state(browser.lw_state, browser.lw);
443                         break;
445                 case LIST_SONGS:
446                         update_metalist(c, g_strdup(artist), NULL);
447                         list_window_reset(browser.lw);
448                         /* restore previous list window state */
449                         list_window_pop_state(browser.lw_state, browser.lw);
450                         break;
451                 }
453                 artist_repaint();
454                 break;
456         case CMD_GO_ROOT_DIRECTORY:
457                 switch (mode) {
458                 case LIST_ARTISTS:
459                         break;
461                 case LIST_ALBUMS:
462                 case LIST_SONGS:
463                         update_metalist(c, NULL, NULL);
464                         list_window_reset(browser.lw);
465                         /* restore first list window state (pop while returning true) */
466                         while(list_window_pop_state(browser.lw_state, browser.lw));
467                         break;
468                 }
470                 artist_repaint();
471                 break;
473         case CMD_SELECT:
474         case CMD_ADD:
475                 switch(mode) {
476                 case LIST_ARTISTS:
477                         selected = g_ptr_array_index(metalist,
478                                                      browser.lw->selected);
479                         add_query(c, MPD_TABLE_ARTIST, selected);
480                         cmd = CMD_LIST_NEXT; /* continue and select next item... */
481                         break;
483                 case LIST_ALBUMS:
484                         if (browser.lw->selected == metalist->len + 1)
485                                 add_query(c, MPD_TABLE_ARTIST, artist);
486                         else if (browser.lw->selected > 0) {
487                                 selected = g_ptr_array_index(metalist,
488                                                              browser.lw->selected - 1);
489                                 add_query(c, MPD_TABLE_ALBUM, selected);
490                                 cmd = CMD_LIST_NEXT; /* continue and select next item... */
491                         }
492                         break;
494                 case LIST_SONGS:
495                         ret = cmd == CMD_SELECT
496                                 ? browser_handle_select(&browser, c)
497                                 : browser_handle_add(&browser, c);
498                         if (ret == 0)
499                                 /* continue and select next item... */
500                                 cmd = CMD_LIST_NEXT;
501                         break;
502                 }
503                 break;
505                 /* continue and update... */
506         case CMD_SCREEN_UPDATE:
507                 update_metalist(c, g_strdup(artist), g_strdup(album));
508                 screen_status_printf(_("Screen updated!"));
509                 return 0;
511         case CMD_LIST_FIND:
512         case CMD_LIST_RFIND:
513         case CMD_LIST_FIND_NEXT:
514         case CMD_LIST_RFIND_NEXT:
515                 if (browser.filelist)
516                         screen_find(screen,
517                                     browser.lw, filelist_length(browser.filelist),
518                                     cmd, browser_lw_callback,
519                                     browser.filelist);
520                 else if (metalist)
521                         screen_find(screen,
522                                     browser.lw, metalist_length(),
523                                     cmd, artist_lw_callback, metalist);
524                 else
525                         return 1;
527                 artist_repaint();
528                 return 1;
530         case CMD_MOUSE_EVENT:
531                 return browser_handle_mouse_event(&browser, c);
533         default:
534                 break;
535         }
537         return 0;
540 const struct screen_functions screen_artist = {
541         .init = init,
542         .exit = quit,
543         .open = open,
544         .resize = resize,
545         .paint = paint,
546         .cmd = artist_cmd,
547         .get_title = get_title,
548 };