1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2009 The Music Player Daemon Project
3 * Project homepage: http://musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "screen_artist.h"
21 #include "screen_interface.h"
22 #include "screen_message.h"
23 #include "screen_find.h"
24 #include "screen_browser.h"
28 #include "mpdclient.h"
29 #include "screen_browser.h"
38 typedef enum { LIST_ARTISTS
, LIST_ALBUMS
, LIST_SONGS
} artist_mode_t
;
40 static artist_mode_t mode
= LIST_ARTISTS
;
41 static GPtrArray
*artist_list
, *album_list
;
42 static char *artist
= NULL
;
43 static char *album
= NULL
;
45 static struct screen_browser browser
;
48 compare_utf8(gconstpointer s1
, gconstpointer s2
)
50 const char *const*t1
= s1
, *const*t2
= s2
;
54 key1
= g_utf8_collate_key(*t1
,-1);
55 key2
= g_utf8_collate_key(*t2
,-1);
56 n
= strcmp(key1
,key2
);
62 /* list_window callback */
64 screen_artist_lw_callback(unsigned idx
, void *data
)
66 GPtrArray
*list
= data
;
67 static char buf
[BUFSIZE
];
70 if (mode
== LIST_ALBUMS
) {
73 else if (idx
== list
->len
+ 1)
74 return _("All tracks");
79 assert(idx
< list
->len
);
81 str_utf8
= g_ptr_array_index(list
, idx
);
82 assert(str_utf8
!= NULL
);
84 str
= utf8_to_locale(str_utf8
);
85 g_strlcpy(buf
, str
, sizeof(buf
));
92 screen_artist_paint(void);
97 screen_artist_paint();
98 wrefresh(browser
.lw
->w
);
102 string_array_free(GPtrArray
*array
)
106 for (i
= 0; i
< array
->len
; ++i
) {
107 char *value
= g_ptr_array_index(array
, i
);
111 g_ptr_array_free(array
, TRUE
);
117 if (artist_list
!= NULL
) {
118 string_array_free(artist_list
);
122 if (album_list
!= NULL
) {
123 string_array_free(album_list
);
127 if (browser
.filelist
) {
128 filelist_free(browser
.filelist
);
129 browser
.filelist
= NULL
;
134 recv_tag_values(struct mpd_connection
*connection
, enum mpd_tag_type tag
,
137 struct mpd_pair
*pair
;
139 while ((pair
= mpd_recv_pair_tag(connection
, tag
)) != NULL
) {
140 g_ptr_array_add(list
, g_strdup(pair
->value
));
141 mpd_return_pair(connection
, pair
);
146 load_artist_list(struct mpdclient
*c
)
148 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
150 assert(mode
== LIST_ARTISTS
);
151 assert(artist
== NULL
);
152 assert(album
== NULL
);
153 assert(artist_list
== NULL
);
154 assert(album_list
== NULL
);
155 assert(browser
.filelist
== NULL
);
157 artist_list
= g_ptr_array_new();
159 if (connection
!= NULL
) {
160 mpd_search_db_tags(connection
, MPD_TAG_ARTIST
);
161 mpd_search_commit(connection
);
162 recv_tag_values(connection
, MPD_TAG_ARTIST
, artist_list
);
164 if (!mpd_response_finish(connection
))
165 mpdclient_handle_error(c
);
169 g_ptr_array_sort(artist_list
, compare_utf8
);
170 list_window_set_length(browser
.lw
, artist_list
->len
);
174 load_album_list(struct mpdclient
*c
)
176 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
178 assert(mode
== LIST_ALBUMS
);
179 assert(artist
!= NULL
);
180 assert(album
== NULL
);
181 assert(album_list
== NULL
);
182 assert(browser
.filelist
== NULL
);
184 album_list
= g_ptr_array_new();
186 if (connection
!= NULL
) {
187 mpd_search_db_tags(connection
, MPD_TAG_ALBUM
);
188 mpd_search_add_tag_constraint(connection
,
189 MPD_OPERATOR_DEFAULT
,
190 MPD_TAG_ARTIST
, artist
);
191 mpd_search_commit(connection
);
193 recv_tag_values(connection
, MPD_TAG_ALBUM
, album_list
);
195 if (!mpd_response_finish(connection
))
196 mpdclient_handle_error(c
);
200 g_ptr_array_sort(album_list
, compare_utf8
);
202 list_window_set_length(browser
.lw
, album_list
->len
+ 2);
206 load_song_list(struct mpdclient
*c
)
208 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
210 assert(mode
== LIST_SONGS
);
211 assert(artist
!= NULL
);
212 assert(album
!= NULL
);
213 assert(browser
.filelist
== NULL
);
215 browser
.filelist
= filelist_new();
216 /* add a dummy entry for ".." */
217 filelist_append(browser
.filelist
, NULL
);
219 if (connection
!= NULL
) {
220 mpd_search_db_songs(connection
, true);
221 mpd_search_add_tag_constraint(connection
, MPD_OPERATOR_DEFAULT
,
222 MPD_TAG_ARTIST
, artist
);
224 mpd_search_add_tag_constraint(connection
, MPD_OPERATOR_DEFAULT
,
225 MPD_TAG_ALBUM
, album
);
226 mpd_search_commit(connection
);
228 filelist_recv(browser
.filelist
, connection
);
230 if (!mpd_response_finish(connection
))
231 mpdclient_handle_error(c
);
235 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
236 list_window_set_length(browser
.lw
, filelist_length(browser
.filelist
));
251 open_artist_list(struct mpdclient
*c
)
260 open_album_list(struct mpdclient
*c
, char *_artist
)
262 assert(_artist
!= NULL
);
272 open_song_list(struct mpdclient
*c
, char *_artist
, char *_album
)
274 assert(_artist
!= NULL
);
275 assert(_album
!= NULL
);
286 reload_lists(struct mpdclient
*c
)
306 screen_artist_init(WINDOW
*w
, int cols
, int rows
)
308 browser
.lw
= list_window_init(w
, cols
, rows
);
314 screen_artist_quit(void)
317 list_window_free(browser
.lw
);
321 screen_artist_open(struct mpdclient
*c
)
323 if (artist_list
== NULL
&& album_list
== NULL
&&
324 browser
.filelist
== NULL
)
329 screen_artist_resize(int cols
, int rows
)
331 list_window_resize(browser
.lw
, cols
, rows
);
335 * Paint one item in the artist list.
338 paint_artist_callback(WINDOW
*w
, unsigned i
,
339 G_GNUC_UNUSED
unsigned y
, unsigned width
,
340 bool selected
, void *data
)
342 GPtrArray
*list
= data
;
343 char *p
= utf8_to_locale(g_ptr_array_index(list
, i
));
345 screen_browser_paint_directory(w
, width
, selected
, p
);
350 * Paint one item in the album list. There are two virtual items
351 * inserted: at the beginning, there's the special item ".." to go to
352 * the parent directory, and at the end, there's the item "All tracks"
353 * to view the tracks of all albums.
356 paint_album_callback(WINDOW
*w
, unsigned i
,
357 G_GNUC_UNUSED
unsigned y
, unsigned width
,
358 bool selected
, void *data
)
360 GPtrArray
*list
= data
;
366 else if (i
== list
->len
+ 1)
369 p
= q
= utf8_to_locale(g_ptr_array_index(list
, i
- 1));
371 screen_browser_paint_directory(w
, width
, selected
, p
);
376 screen_artist_paint(void)
378 if (browser
.filelist
) {
379 screen_browser_paint(&browser
);
380 } else if (album_list
!= NULL
)
381 list_window_paint2(browser
.lw
,
382 paint_album_callback
, album_list
);
383 else if (artist_list
!= NULL
)
384 list_window_paint2(browser
.lw
,
385 paint_artist_callback
, artist_list
);
387 wmove(browser
.lw
->w
, 0, 0);
388 wclrtobot(browser
.lw
->w
);
393 screen_artist_get_title(char *str
, size_t size
)
399 g_snprintf(str
, size
, _("All artists"));
403 s1
= utf8_to_locale(artist
);
404 g_snprintf(str
, size
, _("Albums of artist: %s"), s1
);
409 s1
= utf8_to_locale(artist
);
411 s2
= utf8_to_locale(album
);
412 g_snprintf(str
, size
,
413 _("Album: %s - %s"), s1
, s2
);
416 g_snprintf(str
, size
,
417 _("All tracks of artist: %s"), s1
);
426 screen_artist_update(struct mpdclient
*c
)
428 if (browser
.filelist
== NULL
)
431 if (c
->events
& MPD_IDLE_DATABASE
)
432 /* the db has changed -> update the list */
435 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_QUEUE
))
436 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
438 if (c
->events
& (MPD_IDLE_DATABASE
447 add_query(struct mpdclient
*c
, enum mpd_tag_type table
, char *_filter
)
449 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
451 struct filelist
*addlist
;
453 assert(filter
!= NULL
);
455 if (connection
== NULL
)
458 str
= utf8_to_locale(_filter
);
459 if (table
== MPD_TAG_ALBUM
)
460 screen_status_printf("Adding album %s...", str
);
462 screen_status_printf("Adding %s...", str
);
465 mpd_search_db_songs(connection
, true);
466 mpd_search_add_tag_constraint(connection
, MPD_OPERATOR_DEFAULT
,
468 mpd_search_commit(connection
);
470 addlist
= filelist_new_recv(connection
);
472 if (mpd_response_finish(connection
))
473 mpdclient_filelist_add_all(c
, addlist
);
475 mpdclient_handle_error(c
);
477 filelist_free(addlist
);
481 screen_artist_lw_cmd(struct mpdclient
*c
, command_t cmd
)
486 return list_window_cmd(browser
.lw
, cmd
);
489 return browser_cmd(&browser
, c
, cmd
);
497 string_array_find(GPtrArray
*array
, const char *value
)
501 for (i
= 0; i
< array
->len
; ++i
)
502 if (strcmp((const char*)g_ptr_array_index(array
, i
),
510 screen_artist_cmd(struct mpdclient
*c
, command_t cmd
)
512 struct list_window_range range
;
521 if (browser
.lw
->selected
>= artist_list
->len
)
524 selected
= g_ptr_array_index(artist_list
,
525 browser
.lw
->selected
);
526 open_album_list(c
, g_strdup(selected
));
527 list_window_reset(browser
.lw
);
533 if (browser
.lw
->selected
== 0) {
535 old
= g_strdup(artist
);
538 list_window_reset(browser
.lw
);
539 /* restore previous list window state */
540 idx
= string_array_find(artist_list
, old
);
544 list_window_set_cursor(browser
.lw
, idx
);
545 list_window_center(browser
.lw
, idx
);
547 } else if (browser
.lw
->selected
== album_list
->len
+ 1) {
548 /* handle "show all" */
549 open_song_list(c
, g_strdup(artist
), g_strdup("\0"));
550 list_window_reset(browser
.lw
);
553 selected
= g_ptr_array_index(album_list
,
554 browser
.lw
->selected
- 1);
555 open_song_list(c
, g_strdup(artist
), g_strdup(selected
));
556 list_window_reset(browser
.lw
);
563 if (browser
.lw
->selected
== 0) {
565 old
= g_strdup(album
);
567 open_album_list(c
, g_strdup(artist
));
568 list_window_reset(browser
.lw
);
569 /* restore previous list window state */
571 ? (int)album_list
->len
572 : string_array_find(album_list
, old
);
577 list_window_set_cursor(browser
.lw
, idx
);
578 list_window_center(browser
.lw
, idx
);
588 /* FIXME? CMD_GO_* handling duplicates code from CMD_PLAY */
590 case CMD_GO_PARENT_DIRECTORY
:
596 old
= g_strdup(artist
);
599 list_window_reset(browser
.lw
);
600 /* restore previous list window state */
601 idx
= string_array_find(artist_list
, old
);
605 list_window_set_cursor(browser
.lw
, idx
);
606 list_window_center(browser
.lw
, idx
);
611 old
= g_strdup(album
);
613 open_album_list(c
, g_strdup(artist
));
614 list_window_reset(browser
.lw
);
615 /* restore previous list window state */
617 ? (int)album_list
->len
618 : string_array_find(album_list
, old
);
623 list_window_set_cursor(browser
.lw
, idx
);
624 list_window_center(browser
.lw
, idx
);
632 case CMD_GO_ROOT_DIRECTORY
:
640 list_window_reset(browser
.lw
);
641 /* restore first list window state (pop while returning true) */
653 if (browser
.lw
->selected
>= artist_list
->len
)
656 list_window_get_range(browser
.lw
, &range
);
657 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
658 selected
= g_ptr_array_index(artist_list
, i
);
659 add_query(c
, MPD_TAG_ARTIST
, selected
);
660 cmd
= CMD_LIST_NEXT
; /* continue and select next item... */
665 list_window_get_range(browser
.lw
, &range
);
666 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
667 if(i
== album_list
->len
+ 1)
668 add_query(c
, MPD_TAG_ARTIST
, artist
);
671 selected
= g_ptr_array_index(album_list
,
672 browser
.lw
->selected
- 1);
673 add_query(c
, MPD_TAG_ALBUM
, selected
);
674 cmd
= CMD_LIST_NEXT
; /* continue and select next item... */
680 /* handled by browser_cmd() */
685 /* continue and update... */
686 case CMD_SCREEN_UPDATE
:
692 case CMD_LIST_FIND_NEXT
:
693 case CMD_LIST_RFIND_NEXT
:
696 screen_find(browser
.lw
, cmd
,
697 screen_artist_lw_callback
, artist_list
);
702 screen_find(browser
.lw
, cmd
,
703 screen_artist_lw_callback
, album_list
);
708 /* handled by browser_cmd() */
714 screen_jump(browser
.lw
, screen_artist_lw_callback
,
715 paint_artist_callback
, artist_list
);
720 screen_jump(browser
.lw
, screen_artist_lw_callback
,
721 paint_album_callback
, album_list
);
726 /* handled by browser_cmd() */
736 if (screen_artist_lw_cmd(c
, cmd
)) {
737 if (screen_is_visible(&screen_artist
))
745 const struct screen_functions screen_artist
= {
746 .init
= screen_artist_init
,
747 .exit
= screen_artist_quit
,
748 .open
= screen_artist_open
,
749 .resize
= screen_artist_resize
,
750 .paint
= screen_artist_paint
,
751 .update
= screen_artist_update
,
752 .cmd
= screen_artist_cmd
,
753 .get_title
= screen_artist_get_title
,