Code

81e5653092d7d3e14931a0f54dc93b8e2f872043
[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 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 (mode == LIST_ALBUMS) {
71                 if (idx == 0)
72                         return "[..]";
73                 else if (idx == metalist_length - 1) {
74                         str = utf8_to_locale(_("All tracks"));
75                         g_snprintf(buf, BUFSIZE, "[%s]", str);
76                         g_free(str);
77                         return buf;
78                 }
80                 --idx;
81         }
83         if ((str_utf8 = (char *)g_list_nth_data(metalist, idx)) == NULL)
84                 return NULL;
86         str = utf8_to_locale(str_utf8);
87         g_snprintf(buf, BUFSIZE, "[%s]", str);
88         g_free(str);
90         return buf;
91 }
93 static void
94 paint(mpdclient_t *c);
96 static void
97 artist_repaint(void)
98 {
99         paint(NULL);
100         wrefresh(browser.lw->w);
103 static void
104 artist_repaint_if_active(void)
106         if (screen_is_visible(&screen_artist))
107                 artist_repaint();
110 /* the playlist have been updated -> fix highlights */
111 static void
112 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
114         browser_playlist_changed(&browser, c, event, data);
116         artist_repaint_if_active();
119 /* fetch artists/albums/songs from mpd */
120 static void
121 update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
123         g_free(artist);
124         g_free(album);
125         artist = NULL;
126         album = NULL;
128         if (metalist)
129                 metalist = string_list_free(metalist);
130         if (browser.filelist) {
131                 mpdclient_remove_playlist_callback(c, playlist_changed_callback);
132                 filelist_free(browser.filelist);
133                 browser.filelist = NULL;
134         }
136         if (m_album) {
137                 /* retreive songs... */
138                 artist = m_artist;
139                 album = m_album;
140                 if (album[0] == 0) {
141                         album = g_strdup(_("All tracks"));
142                         browser.filelist =
143                                 mpdclient_filelist_search_utf8(c, TRUE,
144                                                                MPD_TABLE_ARTIST,
145                                                                artist);
146                 } else
147                         browser.filelist =
148                                 mpdclient_filelist_search_utf8(c, TRUE,
149                                                                MPD_TABLE_ALBUM,
150                                                                album);
151                 if (browser.filelist == NULL)
152                         browser.filelist = filelist_new(NULL);
154                 /* add a dummy entry for ".." */
155                 filelist_prepend(browser.filelist, NULL);
157                 /* install playlist callback and fix highlights */
158                 sync_highlights(c, browser.filelist);
159                 mpdclient_install_playlist_callback(c, playlist_changed_callback);
160                 mode = LIST_SONGS;
161         } else if (m_artist) {
162                 /* retreive albums... */
164                 artist = m_artist;
165                 metalist = mpdclient_get_albums_utf8(c, m_artist);
166                 /* sort list */
167                 metalist = g_list_sort(metalist, compare_utf8);
168                 mode = LIST_ALBUMS;
169         } else {
170                 /* retreive artists... */
172                 metalist = mpdclient_get_artists_utf8(c);
173                 /* sort list */
174                 metalist = g_list_sort(metalist, compare_utf8);
175                 mode = LIST_ARTISTS;
176         }
177         metalist_length = g_list_length(metalist);
178         if (mode == LIST_ALBUMS)
179                 metalist_length += 2;
182 /* db updated */
183 static void
184 browse_callback(mpdclient_t *c, int event, mpd_unused gpointer data)
186         switch(event) {
187         case BROWSE_DB_UPDATED:
188                 D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
189                 update_metalist(c, g_strdup(artist), g_strdup(album));
190                 break;
191         default:
192                 break;
193         }
195         artist_repaint_if_active();
198 static void
199 init(WINDOW *w, int cols, int rows)
201         browser.lw = list_window_init(w, cols, rows);
202         browser.lw_state = list_window_init_state();
203         artist = NULL;
204         album = NULL;
207 static void
208 quit(void)
210         if (browser.filelist)
211                 filelist_free(browser.filelist);
212         if (metalist)
213                 string_list_free(metalist);
214         g_free(artist);
215         g_free(album);
216         artist = NULL;
217         album = NULL;
218         list_window_free(browser.lw);
219         list_window_free_state(browser.lw_state);
222 static void
223 open(mpd_unused screen_t *screen, mpdclient_t *c)
225         static gboolean callback_installed = FALSE;
227         if (metalist == NULL && browser.filelist == NULL)
228                 update_metalist(c, NULL, NULL);
229         if (!callback_installed) {
230                 mpdclient_install_browse_callback(c, browse_callback);
231                 callback_installed = TRUE;
232         }
235 static void
236 resize(int cols, int rows)
238         browser.lw->cols = cols;
239         browser.lw->rows = rows;
242 static void
243 paint(mpd_unused mpdclient_t *c)
245         if (browser.filelist) {
246                 list_window_paint(browser.lw, browser_lw_callback,
247                                   browser.filelist);
248         } else if (metalist) {
249                 list_window_paint(browser.lw, artist_lw_callback, metalist);
250         } else {
251                 wmove(browser.lw->w, 0, 0);
252                 wclrtobot(browser.lw->w);
253         }
256 static const char *
257 get_title(char *str, size_t size)
259         char *s1 = artist ? utf8_to_locale(artist) : NULL;
260         char *s2 = album ? utf8_to_locale(album) : NULL;
262         switch(mode) {
263         case LIST_ARTISTS:
264                 g_snprintf(str, size,  _("Artist: [db browser - EXPERIMENTAL]"));
265                 break;
266         case LIST_ALBUMS:
267                 g_snprintf(str, size,  _("Artist: %s"), s1);
268                 break;
269         case LIST_SONGS:
270                 g_snprintf(str, size,  _("Artist: %s - %s"), s1, s2);
271                 break;
272         }
273         g_free(s1);
274         g_free(s2);
275         return str;
278 static void
279 add_query(mpdclient_t *c, int table, char *_filter)
281         char *str;
282         mpdclient_filelist_t *addlist;
284         assert(filter != NULL);
286         str = utf8_to_locale(_filter);
287         if (table== MPD_TABLE_ALBUM)
288                 screen_status_printf("Adding album %s...", str);
289         else
290                 screen_status_printf("Adding %s...", str);
291         g_free(str);
293         addlist = mpdclient_filelist_search_utf8(c, TRUE, table, _filter);
294         if (addlist) {
295                 mpdclient_filelist_add_all(c, addlist);
296                 filelist_free(addlist);
297         }
300 static int
301 artist_lw_cmd(command_t cmd)
303         switch (mode) {
304         case LIST_ARTISTS:
305         case LIST_ALBUMS:
306                 return list_window_cmd(browser.lw, metalist_length, cmd);
308         case LIST_SONGS:
309                 return list_window_cmd(browser.lw,
310                                        filelist_length(browser.filelist),
311                                        cmd);
312         }
314         assert(0);
315         return 0;
318 static int
319 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
321         char *selected;
322         int ret;
324         if (artist_lw_cmd(cmd)) {
325                 artist_repaint();
326                 wrefresh(browser.lw->w);
327                 return 1;
328         }
330         switch(cmd) {
331         case CMD_PLAY:
332                 switch (mode) {
333                 case LIST_ARTISTS:
334                         selected = (char *) g_list_nth_data(metalist,
335                                                             browser.lw->selected);
336                         update_metalist(c, g_strdup(selected), NULL);
337                         list_window_push_state(browser.lw_state, browser.lw);
339                         list_window_paint(browser.lw, artist_lw_callback, metalist);
340                         wrefresh(browser.lw->w);
341                         break;
343                 case LIST_ALBUMS:
344                         if (browser.lw->selected == 0) {
345                                 /* handle ".." */
347                                 update_metalist(c, NULL, NULL);
348                                 list_window_reset(browser.lw);
349                                 /* restore previous list window state */
350                                 list_window_pop_state(browser.lw_state, browser.lw);
351                         } else if (browser.lw->selected == metalist_length - 1) {
352                                 /* handle "show all" */
353                                 update_metalist(c, g_strdup(artist), g_strdup("\0"));
354                                 list_window_push_state(browser.lw_state, browser.lw);
355                         } else {
356                                 /* select album */
357                                 selected = g_list_nth_data(metalist,
358                                                            browser.lw->selected - 1);
359                                 update_metalist(c, g_strdup(artist), g_strdup(selected));
360                                 list_window_push_state(browser.lw_state, browser.lw);
361                         }
363                         artist_repaint();
364                         break;
366                 case LIST_SONGS:
367                         if (browser.lw->selected == 0) {
368                                 /* handle ".." */
370                                 update_metalist(c, g_strdup(artist), NULL);
371                                 list_window_reset(browser.lw);
372                                 /* restore previous list window state */
373                                 list_window_pop_state(browser.lw_state,
374                                                       browser.lw);
376                                 list_window_paint(browser.lw, artist_lw_callback, metalist);
377                                 wrefresh(browser.lw->w);
378                         } else
379                                 browser_handle_enter(&browser, c);
380                         break;
381                 }
382                 return 1;
385                 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
387         case CMD_GO_PARENT_DIRECTORY:
388                 switch (mode) {
389                 case LIST_ARTISTS:
390                         break;
392                 case LIST_ALBUMS:
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                         break;
399                 case LIST_SONGS:
400                         update_metalist(c, g_strdup(artist), NULL);
401                         list_window_reset(browser.lw);
402                         /* restore previous list window state */
403                         list_window_pop_state(browser.lw_state, browser.lw);
404                         break;
405                 }
407                 artist_repaint();
408                 break;
410         case CMD_GO_ROOT_DIRECTORY:
411                 switch (mode) {
412                 case LIST_ARTISTS:
413                         break;
415                 case LIST_ALBUMS:
416                 case LIST_SONGS:
417                         update_metalist(c, NULL, NULL);
418                         list_window_reset(browser.lw);
419                         /* restore first list window state (pop while returning true) */
420                         while(list_window_pop_state(browser.lw_state, browser.lw));
421                         break;
422                 }
424                 artist_repaint();
425                 break;
427         case CMD_SELECT:
428         case CMD_ADD:
429                 switch(mode) {
430                 case LIST_ARTISTS:
431                         selected = g_list_nth_data(metalist,
432                                                    browser.lw->selected);
433                         if (selected == NULL)
434                                 return 1;
436                         add_query(c, MPD_TABLE_ARTIST, selected);
437                         cmd = CMD_LIST_NEXT; /* continue and select next item... */
438                         break;
440                 case LIST_ALBUMS:
441                         if (browser.lw->selected &&
442                             browser.lw->selected == metalist_length - 1)
443                                 add_query(c, MPD_TABLE_ARTIST, artist);
444                         else if (browser.lw->selected > 0) {
445                                 selected = g_list_nth_data(metalist,
446                                                            browser.lw->selected - 1);
447                                 if (selected == NULL)
448                                         return 1;
450                                 add_query(c, MPD_TABLE_ALBUM, selected);
451                                 cmd = CMD_LIST_NEXT; /* continue and select next item... */
452                         }
453                         break;
455                 case LIST_SONGS:
456                         ret = cmd == CMD_SELECT
457                                 ? browser_handle_select(&browser, c)
458                                 : browser_handle_add(&browser, c);
459                         if (ret == 0)
460                                 /* continue and select next item... */
461                                 cmd = CMD_LIST_NEXT;
462                         break;
463                 }
464                 break;
466                 /* continue and update... */
467         case CMD_SCREEN_UPDATE:
468                 update_metalist(c, g_strdup(artist), g_strdup(album));
469                 screen_status_printf(_("Screen updated!"));
470                 return 0;
472         case CMD_LIST_FIND:
473         case CMD_LIST_RFIND:
474         case CMD_LIST_FIND_NEXT:
475         case CMD_LIST_RFIND_NEXT:
476                 if (browser.filelist)
477                         screen_find(screen,
478                                     browser.lw, filelist_length(browser.filelist),
479                                     cmd, browser_lw_callback,
480                                     browser.filelist);
481                 else if (metalist)
482                         screen_find(screen,
483                                     browser.lw, metalist_length,
484                                     cmd, artist_lw_callback, metalist);
485                 else
486                         return 1;
488                 artist_repaint();
489                 return 1;
491         case CMD_MOUSE_EVENT:
492                 return browser_handle_mouse_event(&browser, c);
494         default:
495                 break;
496         }
498         return 0;
501 const struct screen_functions screen_artist = {
502         .init = init,
503         .exit = quit,
504         .open = open,
505         .resize = resize,
506         .paint = paint,
507         .cmd = artist_cmd,
508         .get_title = get_title,
509 };