Code

screen_artist: call artist_lw_cmd() at the end of artist_cmd()
[ncmpc.git] / src / screen_artist.c
index 07a3f8f649f95788131293d2bd03cc48fdbd92bf..c9c6f9b019a1acc4e569f8aebe8cc07d361f2796 100644 (file)
 typedef enum { LIST_ARTISTS, LIST_ALBUMS, LIST_SONGS } artist_mode_t;
 
 static artist_mode_t mode = LIST_ARTISTS;
+static GPtrArray *artist_list, *album_list;
 static char *artist = NULL;
 static char *album  = NULL;
-static unsigned metalist_length = 0;
-static GList *metalist = NULL;
 
 static struct screen_browser browser;
 
@@ -64,12 +63,29 @@ compare_utf8(gconstpointer s1, gconstpointer s2)
 static const char *
 artist_lw_callback(unsigned idx, mpd_unused int *highlight, mpd_unused void *data)
 {
+       GPtrArray *list = data;
        static char buf[BUFSIZE];
        char *str, *str_utf8;
 
-       if ((str_utf8 = (char *)g_list_nth_data(metalist, idx)) == NULL)
+       if (mode == LIST_ALBUMS) {
+               if (idx == 0)
+                       return "[..]";
+               else if (idx == list->len + 1) {
+                       str = utf8_to_locale(_("All tracks"));
+                       g_snprintf(buf, BUFSIZE, "[%s]", str);
+                       g_free(str);
+                       return buf;
+               }
+
+               --idx;
+       }
+
+       if (idx >= list->len)
                return NULL;
 
+       str_utf8 = g_ptr_array_index(list, idx);
+       assert(str_utf8 != NULL);
+
        str = utf8_to_locale(str_utf8);
        g_snprintf(buf, BUFSIZE, "[%s]", str);
        g_free(str);
@@ -103,69 +119,186 @@ playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
        artist_repaint_if_active();
 }
 
-/* fetch artists/albums/songs from mpd */
+static GPtrArray *
+g_list_to_ptr_array(GList *in)
+{
+       GPtrArray *out = g_ptr_array_sized_new(g_list_length(in));
+       GList *head = in;
+
+       while (in != NULL) {
+               g_ptr_array_add(out, in->data);
+               in = g_list_next(in);
+       }
+
+       g_list_free(head);
+       return out;
+}
+
 static void
-update_metalist(mpdclient_t *c, char *m_artist, char *m_album)
+string_array_free(GPtrArray *array)
 {
-       g_free(artist);
-       g_free(album);
-       artist = NULL;
-       album = NULL;
+       unsigned i;
+
+       for (i = 0; i < array->len; ++i) {
+               char *value = g_ptr_array_index(array, i);
+               free(value);
+       }
+
+       g_ptr_array_free(array, TRUE);
+}
+
+static void
+free_lists(struct mpdclient *c)
+{
+       if (artist_list != NULL) {
+               string_array_free(artist_list);
+               artist_list = NULL;
+       }
+
+       if (album_list != NULL) {
+               string_array_free(album_list);
+               album_list = NULL;
+       }
 
-       if (metalist)
-               metalist = string_list_free(metalist);
        if (browser.filelist) {
-               mpdclient_remove_playlist_callback(c, playlist_changed_callback);
+               if (c != NULL)
+                       mpdclient_remove_playlist_callback(c, playlist_changed_callback);
                filelist_free(browser.filelist);
                browser.filelist = NULL;
        }
+}
+
+static void
+load_artist_list(struct mpdclient *c)
+{
+       GList *list;
+
+       assert(mode == LIST_ARTISTS);
+       assert(artist == NULL);
+       assert(album == NULL);
+       assert(artist_list == NULL);
+       assert(album_list == NULL);
+       assert(browser.filelist == NULL);
+
+       list = mpdclient_get_artists_utf8(c);
+       /* sort list */
+       list = g_list_sort(list, compare_utf8);
+
+       artist_list = g_list_to_ptr_array(list);
+}
+
+static void
+load_album_list(struct mpdclient *c)
+{
+       GList *list;
+
+       assert(mode == LIST_ALBUMS);
+       assert(artist != NULL);
+       assert(album == NULL);
+       assert(album_list == NULL);
+       assert(browser.filelist == NULL);
+
+       list = mpdclient_get_albums_utf8(c, artist);
+       /* sort list */
+       list = g_list_sort(list, compare_utf8);
+
+       album_list = g_list_to_ptr_array(list);
+}
+
+static void
+load_song_list(struct mpdclient *c)
+{
+       assert(mode == LIST_SONGS);
+       assert(artist != NULL);
+       assert(album != NULL);
+       assert(browser.filelist == NULL);
+
+       if (album[0] == 0) {
+               album = g_strdup(_("All tracks"));
+               browser.filelist =
+                       mpdclient_filelist_search_utf8(c, TRUE,
+                                                      MPD_TABLE_ARTIST,
+                                                      artist);
+       } else
+               browser.filelist =
+                       mpdclient_filelist_search_utf8(c, TRUE,
+                                                      MPD_TABLE_ALBUM,
+                                                      album);
+       if (browser.filelist == NULL)
+               browser.filelist = filelist_new(NULL);
+
+       /* add a dummy entry for ".." */
+       filelist_prepend(browser.filelist, NULL);
+
+       /* install playlist callback and fix highlights */
+       sync_highlights(c, browser.filelist);
+       mpdclient_install_playlist_callback(c, playlist_changed_callback);
+}
+
+static void
+free_state(struct mpdclient *c)
+{
+       g_free(artist);
+       g_free(album);
+       artist = NULL;
+       album = NULL;
+
+       free_lists(c);
+}
+
+static void
+open_artist_list(struct mpdclient *c)
+{
+       free_state(c);
+
+       mode = LIST_ARTISTS;
+       load_artist_list(c);
+}
+
+static void
+open_album_list(struct mpdclient *c, char *_artist)
+{
+       assert(_artist != NULL);
+
+       free_state(c);
 
-       if (m_album) {
-               /* retreive songs... */
-               artist = m_artist;
-               album = m_album;
-               if (album[0] == 0) {
-                       album = g_strdup(_("All tracks"));
-                       browser.filelist =
-                               mpdclient_filelist_search_utf8(c, TRUE,
-                                                              MPD_TABLE_ARTIST,
-                                                              artist);
-               } else
-                       browser.filelist =
-                               mpdclient_filelist_search_utf8(c, TRUE,
-                                                              MPD_TABLE_ALBUM,
-                                                              album);
-               if (browser.filelist == NULL)
-                       browser.filelist = filelist_new(NULL);
-
-               /* add a dummy entry for ".." */
-               filelist_prepend(browser.filelist, NULL);
-
-               /* install playlist callback and fix highlights */
-               sync_highlights(c, browser.filelist);
-               mpdclient_install_playlist_callback(c, playlist_changed_callback);
-               mode = LIST_SONGS;
-       } else if (m_artist) {
-               /* retreive albums... */
-
-               artist = m_artist;
-               metalist = mpdclient_get_albums_utf8(c, m_artist);
-               /* sort list */
-               metalist = g_list_sort(metalist, compare_utf8);
-               /* add a dummy entry for ".." */
-               metalist = g_list_insert(metalist, g_strdup(".."), 0);
-               /* add a dummy entry for all songs */
-               metalist = g_list_insert(metalist, g_strdup(_("All tracks")), -1);
-               mode = LIST_ALBUMS;
-       } else {
-               /* retreive artists... */
-
-               metalist = mpdclient_get_artists_utf8(c);
-               /* sort list */
-               metalist = g_list_sort(metalist, compare_utf8);
-               mode = LIST_ARTISTS;
+       mode = LIST_ALBUMS;
+       artist = _artist;
+       load_album_list(c);
+}
+
+static void
+open_song_list(struct mpdclient *c, char *_artist, char *_album)
+{
+       assert(_artist != NULL);
+       assert(_album != NULL);
+
+       free_state(c);
+
+       mode = LIST_SONGS;
+       artist = _artist;
+       album = _album;
+       load_song_list(c);
+}
+
+static void
+reload_lists(struct mpdclient *c)
+{
+       free_lists(c);
+
+       switch (mode) {
+       case LIST_ARTISTS:
+               load_artist_list(c);
+               break;
+
+       case LIST_ALBUMS:
+               load_album_list(c);
+               break;
+
+       case LIST_SONGS:
+               load_song_list(c);
+               break;
        }
-       metalist_length = g_list_length(metalist);
 }
 
 /* db updated */
@@ -175,7 +308,7 @@ browse_callback(mpdclient_t *c, int event, mpd_unused gpointer data)
        switch(event) {
        case BROWSE_DB_UPDATED:
                D("screen_artist.c> browse_callback() [BROWSE_DB_UPDATED]\n");
-               update_metalist(c, g_strdup(artist), g_strdup(album));
+               reload_lists(c);
                break;
        default:
                break;
@@ -196,14 +329,7 @@ init(WINDOW *w, int cols, int rows)
 static void
 quit(void)
 {
-       if (browser.filelist)
-               filelist_free(browser.filelist);
-       if (metalist)
-               string_list_free(metalist);
-       g_free(artist);
-       g_free(album);
-       artist = NULL;
-       album = NULL;
+       free_state(NULL);
        list_window_free(browser.lw);
        list_window_free_state(browser.lw_state);
 }
@@ -213,8 +339,9 @@ open(mpd_unused screen_t *screen, mpdclient_t *c)
 {
        static gboolean callback_installed = FALSE;
 
-       if (metalist == NULL && browser.filelist == NULL)
-               update_metalist(c, NULL, NULL);
+       if (artist_list == NULL && album_list == NULL &&
+           browser.filelist == NULL)
+               reload_lists(c);
        if (!callback_installed) {
                mpdclient_install_browse_callback(c, browse_callback);
                callback_installed = TRUE;
@@ -234,9 +361,11 @@ paint(mpd_unused mpdclient_t *c)
        if (browser.filelist) {
                list_window_paint(browser.lw, browser_lw_callback,
                                  browser.filelist);
-       } else if (metalist) {
-               list_window_paint(browser.lw, artist_lw_callback, metalist);
-       } else {
+       } else if (album_list != NULL)
+               list_window_paint(browser.lw, artist_lw_callback, album_list);
+       else if (artist_list != NULL)
+               list_window_paint(browser.lw, artist_lw_callback, artist_list);
+       else {
                wmove(browser.lw->w, 0, 0);
                wclrtobot(browser.lw->w);
        }
@@ -286,49 +415,70 @@ add_query(mpdclient_t *c, int table, char *_filter)
        }
 }
 
+static unsigned
+metalist_length(void)
+{
+       assert(mode != LIST_ARTISTS || artist_list != NULL);
+       assert(mode != LIST_ALBUMS || album_list != NULL);
+
+       return mode == LIST_ALBUMS
+               ? album_list->len + 2
+               : artist_list->len;
+}
+
+static int
+artist_lw_cmd(command_t cmd)
+{
+       switch (mode) {
+       case LIST_ARTISTS:
+       case LIST_ALBUMS:
+               return list_window_cmd(browser.lw, metalist_length(), cmd);
+
+       case LIST_SONGS:
+               return list_window_cmd(browser.lw,
+                                      filelist_length(browser.filelist),
+                                      cmd);
+       }
+
+       assert(0);
+       return 0;
+}
+
 static int
 artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
 {
        char *selected;
        int ret;
 
-       if (browser.filelist == NULL && metalist != NULL &&
-           list_window_cmd(browser.lw, metalist_length, cmd)) {
-               list_window_paint(browser.lw, artist_lw_callback, metalist);
-               wrefresh(browser.lw->w);
-               return 1;
-       }
-
        switch(cmd) {
        case CMD_PLAY:
                switch (mode) {
                case LIST_ARTISTS:
-                       selected = (char *) g_list_nth_data(metalist,
-                                                           browser.lw->selected);
-                       update_metalist(c, g_strdup(selected), NULL);
+                       selected = g_ptr_array_index(artist_list,
+                                                    browser.lw->selected);
+                       open_album_list(c, g_strdup(selected));
                        list_window_push_state(browser.lw_state, browser.lw);
 
-                       list_window_paint(browser.lw, artist_lw_callback, metalist);
-                       wrefresh(browser.lw->w);
+                       artist_repaint();
                        break;
 
                case LIST_ALBUMS:
                        if (browser.lw->selected == 0) {
                                /* handle ".." */
 
-                               update_metalist(c, NULL, NULL);
+                               open_artist_list(c);
                                list_window_reset(browser.lw);
                                /* restore previous list window state */
                                list_window_pop_state(browser.lw_state, browser.lw);
-                       } else if (browser.lw->selected == metalist_length - 1) {
+                       } else if (browser.lw->selected == album_list->len + 1) {
                                /* handle "show all" */
-                               update_metalist(c, g_strdup(artist), g_strdup("\0"));
+                               open_song_list(c, g_strdup(artist), g_strdup("\0"));
                                list_window_push_state(browser.lw_state, browser.lw);
                        } else {
                                /* select album */
-                               selected = g_list_nth_data(metalist,
-                                                          browser.lw->selected);
-                               update_metalist(c, g_strdup(artist), g_strdup(selected));
+                               selected = g_ptr_array_index(album_list,
+                                                            browser.lw->selected - 1);
+                               open_song_list(c, g_strdup(artist), g_strdup(selected));
                                list_window_push_state(browser.lw_state, browser.lw);
                        }
 
@@ -339,14 +489,13 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
                        if (browser.lw->selected == 0) {
                                /* handle ".." */
 
-                               update_metalist(c, g_strdup(artist), NULL);
+                               open_album_list(c, g_strdup(artist));
                                list_window_reset(browser.lw);
                                /* restore previous list window state */
                                list_window_pop_state(browser.lw_state,
                                                      browser.lw);
 
-                               list_window_paint(browser.lw, artist_lw_callback, metalist);
-                               wrefresh(browser.lw->w);
+                               artist_repaint();
                        } else
                                browser_handle_enter(&browser, c);
                        break;
@@ -362,14 +511,14 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
                        break;
 
                case LIST_ALBUMS:
-                       update_metalist(c, NULL, NULL);
+                       open_artist_list(c);
                        list_window_reset(browser.lw);
                        /* restore previous list window state */
                        list_window_pop_state(browser.lw_state, browser.lw);
                        break;
 
                case LIST_SONGS:
-                       update_metalist(c, g_strdup(artist), NULL);
+                       open_album_list(c, g_strdup(artist));
                        list_window_reset(browser.lw);
                        /* restore previous list window state */
                        list_window_pop_state(browser.lw_state, browser.lw);
@@ -386,7 +535,7 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
 
                case LIST_ALBUMS:
                case LIST_SONGS:
-                       update_metalist(c, NULL, NULL);
+                       open_artist_list(c);
                        list_window_reset(browser.lw);
                        /* restore first list window state (pop while returning true) */
                        while(list_window_pop_state(browser.lw_state, browser.lw));
@@ -400,25 +549,18 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
        case CMD_ADD:
                switch(mode) {
                case LIST_ARTISTS:
-                       selected = g_list_nth_data(metalist,
-                                                  browser.lw->selected);
-                       if (selected == NULL)
-                               return 1;
-
+                       selected = g_ptr_array_index(artist_list,
+                                                    browser.lw->selected);
                        add_query(c, MPD_TABLE_ARTIST, selected);
                        cmd = CMD_LIST_NEXT; /* continue and select next item... */
                        break;
 
                case LIST_ALBUMS:
-                       if (browser.lw->selected &&
-                           browser.lw->selected == metalist_length - 1)
+                       if (browser.lw->selected == album_list->len + 1)
                                add_query(c, MPD_TABLE_ARTIST, artist);
                        else if (browser.lw->selected > 0) {
-                               selected = g_list_nth_data(metalist,
-                                                          browser.lw->selected);
-                               if (selected == NULL)
-                                       return 1;
-
+                               selected = g_ptr_array_index(album_list,
+                                                            browser.lw->selected - 1);
                                add_query(c, MPD_TABLE_ALBUM, selected);
                                cmd = CMD_LIST_NEXT; /* continue and select next item... */
                        }
@@ -437,7 +579,7 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
 
                /* continue and update... */
        case CMD_SCREEN_UPDATE:
-               update_metalist(c, g_strdup(artist), g_strdup(album));
+               reload_lists(c);
                screen_status_printf(_("Screen updated!"));
                return 0;
 
@@ -445,17 +587,27 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
        case CMD_LIST_RFIND:
        case CMD_LIST_FIND_NEXT:
        case CMD_LIST_RFIND_NEXT:
-               if (browser.filelist)
+               switch (mode) {
+               case LIST_ARTISTS:
+                       screen_find(screen,
+                                   browser.lw, artist_list->len,
+                                   cmd, artist_lw_callback, artist_list);
+                       break;
+
+               case LIST_ALBUMS:
                        screen_find(screen,
-                                   browser.lw, filelist_length(browser.filelist),
+                                   browser.lw, album_list->len + 2,
+                                   cmd, artist_lw_callback, album_list);
+                       break;
+
+               case LIST_SONGS:
+                       screen_find(screen,
+                                   browser.lw,
+                                   filelist_length(browser.filelist),
                                    cmd, browser_lw_callback,
                                    browser.filelist);
-               else if (metalist)
-                       screen_find(screen,
-                                   browser.lw, metalist_length,
-                                   cmd, artist_lw_callback, metalist);
-               else
-                       return 1;
+                       break;
+               }
 
                artist_repaint();
                return 1;
@@ -467,12 +619,8 @@ artist_cmd(screen_t *screen, mpdclient_t *c, command_t cmd)
                break;
        }
 
-       if (browser.filelist != NULL &&
-           list_window_cmd(browser.lw, filelist_length(browser.filelist),
-                           cmd)) {
-               list_window_paint(browser.lw, browser_lw_callback,
-                                 browser.filelist);
-               wrefresh(browser.lw->w);
+       if (artist_lw_cmd(cmd)) {
+               artist_repaint();
                return 1;
        }