1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2010 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_file.h"
21 #include "screen_browser.h"
22 #include "screen_interface.h"
23 #include "screen_message.h"
24 #include "screen_queue.h"
29 #include "mpdclient.h"
31 #include "screen_utils.h"
32 #include "screen_client.h"
34 #include <mpd/client.h>
41 static struct screen_browser browser
;
42 static char *current_path
;
45 screen_file_paint(void);
48 screen_file_repaint(void)
51 wrefresh(browser
.lw
->w
);
55 screen_file_load_list(struct mpdclient
*c
, struct filelist
*filelist
)
57 struct mpd_connection
*connection
;
59 connection
= mpdclient_get_connection(c
);
60 if (connection
== NULL
)
63 mpd_send_list_meta(connection
, current_path
);
64 filelist_recv(filelist
, connection
);
66 if (mpd_response_finish(connection
))
67 filelist_sort_dir_play(filelist
, compare_filelist_entry_path
);
69 mpdclient_handle_error(c
);
73 screen_file_reload(struct mpdclient
*c
)
75 if (browser
.filelist
!= NULL
)
76 filelist_free(browser
.filelist
);
78 browser
.filelist
= filelist_new();
79 if (*current_path
!= 0)
80 /* add a dummy entry for ./.. */
81 filelist_append(browser
.filelist
, NULL
);
83 screen_file_load_list(c
, browser
.filelist
);
85 list_window_set_length(browser
.lw
,
86 filelist_length(browser
.filelist
));
90 * Change to the specified absolute directory.
93 change_directory(struct mpdclient
*c
, const char *new_path
)
96 current_path
= g_strdup(new_path
);
98 screen_file_reload(c
);
100 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
102 list_window_reset(browser
.lw
);
104 return browser
.filelist
!= NULL
;
108 * Change to the parent directory of the current directory.
111 change_to_parent(struct mpdclient
*c
)
113 char *parent
= g_path_get_dirname(current_path
);
118 if (strcmp(parent
, ".") == 0)
121 old_path
= current_path
;
124 success
= change_directory(c
, parent
);
128 ? filelist_find_directory(browser
.filelist
, old_path
)
132 if (success
&& idx
>= 0) {
133 /* set the cursor on the previous working directory */
134 list_window_set_cursor(browser
.lw
, idx
);
135 list_window_center(browser
.lw
, idx
);
142 * Change to the directory referred by the specified #filelist_entry
146 change_to_entry(struct mpdclient
*c
, const struct filelist_entry
*entry
)
148 assert(entry
!= NULL
);
150 if (entry
->entity
== NULL
)
151 return change_to_parent(c
);
152 else if (mpd_entity_get_type(entry
->entity
) == MPD_ENTITY_TYPE_DIRECTORY
)
153 return change_directory(c
, mpd_directory_get_path(mpd_entity_get_directory(entry
->entity
)));
159 screen_file_handle_enter(struct mpdclient
*c
)
161 const struct filelist_entry
*entry
= browser_get_selected_entry(&browser
);
166 return change_to_entry(c
, entry
);
170 handle_save(struct mpdclient
*c
)
172 struct list_window_range range
;
173 const char *defaultname
= NULL
;
174 char *defaultname_utf8
= NULL
;
176 list_window_get_range(browser
.lw
, &range
);
177 if (range
.start
== range
.end
)
180 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
181 struct filelist_entry
*entry
=
182 filelist_get(browser
.filelist
, i
);
183 if( entry
&& entry
->entity
) {
184 struct mpd_entity
*entity
= entry
->entity
;
185 if (mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_PLAYLIST
) {
186 const struct mpd_playlist
*playlist
=
187 mpd_entity_get_playlist(entity
);
188 defaultname
= mpd_playlist_get_path(playlist
);
194 defaultname_utf8
= utf8_to_locale(defaultname
);
195 playlist_save(c
, NULL
, defaultname_utf8
);
196 g_free(defaultname_utf8
);
200 handle_delete(struct mpdclient
*c
)
202 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
203 struct list_window_range range
;
204 struct mpd_entity
*entity
;
205 const struct mpd_playlist
*playlist
;
209 if (connection
== NULL
)
212 list_window_get_range(browser
.lw
, &range
);
213 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
214 struct filelist_entry
*entry
=
215 filelist_get(browser
.filelist
, i
);
216 if( entry
==NULL
|| entry
->entity
==NULL
)
219 entity
= entry
->entity
;
221 if (mpd_entity_get_type(entity
) != MPD_ENTITY_TYPE_PLAYLIST
) {
222 /* translators: the "delete" command is only possible
223 for playlists; the user attempted to delete a song
224 or a directory or something else */
225 screen_status_printf(_("Deleting this item is not possible"));
230 playlist
= mpd_entity_get_playlist(entity
);
231 str
= utf8_to_locale(g_basename(mpd_playlist_get_path(playlist
)));
232 buf
= g_strdup_printf(_("Delete playlist %s [%s/%s] ? "), str
, YES
, NO
);
234 key
= tolower(screen_getch(buf
));
236 if( key
!= YES
[0] ) {
237 /* translators: a dialog was aborted by the user */
238 screen_status_printf(_("Aborted"));
242 if (!mpd_run_rm(connection
, mpd_playlist_get_path(playlist
))) {
243 mpdclient_handle_error(c
);
247 c
->events
|= MPD_IDLE_STORED_PLAYLIST
;
249 /* translators: MPD deleted the playlist, as requested by the
251 screen_status_printf(_("Playlist deleted"));
256 screen_file_init(WINDOW
*w
, int cols
, int rows
)
258 current_path
= g_strdup("");
260 browser
.lw
= list_window_init(w
, cols
, rows
);
264 screen_file_resize(int cols
, int rows
)
266 list_window_resize(browser
.lw
, cols
, rows
);
270 screen_file_exit(void)
272 if (browser
.filelist
)
273 filelist_free(browser
.filelist
);
274 list_window_free(browser
.lw
);
276 g_free(current_path
);
280 screen_file_open(struct mpdclient
*c
)
282 screen_file_reload(c
);
283 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
287 screen_file_get_title(char *str
, size_t size
)
289 const char *path
= NULL
, *prev
= NULL
, *slash
= current_path
;
292 /* determine the last 2 parts of the path */
293 while ((slash
= strchr(slash
, '/')) != NULL
) {
299 /* fall back to full path */
302 path_locale
= utf8_to_locale(path
);
303 g_snprintf(str
, size
, "%s: %s",
304 /* translators: caption of the browser screen */
305 _("Browse"), path_locale
);
311 screen_file_paint(void)
313 screen_browser_paint(&browser
);
317 screen_file_update(struct mpdclient
*c
)
319 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
)) {
320 /* the db has changed -> update the filelist */
321 screen_file_reload(c
);
324 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
329 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
330 screen_file_repaint();
335 screen_file_cmd(struct mpdclient
*c
, command_t cmd
)
339 if (screen_file_handle_enter(c
)) {
340 screen_file_repaint();
346 case CMD_GO_ROOT_DIRECTORY
:
347 change_directory(c
, "");
348 screen_file_repaint();
350 case CMD_GO_PARENT_DIRECTORY
:
352 screen_file_repaint();
356 /* don't let browser_cmd() evaluate the locate command
357 - it's a no-op, and by the way, leads to a
358 segmentation fault in the current implementation */
361 case CMD_SCREEN_UPDATE
:
362 screen_file_reload(c
);
363 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
364 screen_file_repaint();
371 if (browser_cmd(&browser
, c
, cmd
)) {
372 if (screen_is_visible(&screen_browse
))
373 screen_file_repaint();
377 if (!mpdclient_is_connected(c
))
383 screen_file_repaint();
386 case CMD_SAVE_PLAYLIST
:
391 screen_database_update(c
, current_path
);
401 const struct screen_functions screen_browse
= {
402 .init
= screen_file_init
,
403 .exit
= screen_file_exit
,
404 .open
= screen_file_open
,
405 .resize
= screen_file_resize
,
406 .paint
= screen_file_paint
,
407 .update
= screen_file_update
,
408 .cmd
= screen_file_cmd
,
409 .get_title
= screen_file_get_title
,
413 screen_file_goto_song(struct mpdclient
*c
, const struct mpd_song
*song
)
415 const char *uri
, *slash
, *parent
;
416 char *allocated
= NULL
;
420 assert(song
!= NULL
);
422 uri
= mpd_song_get_uri(song
);
424 if (strstr(uri
, "//") != NULL
)
428 /* determine the song's parent directory and go there */
430 slash
= strrchr(uri
, '/');
432 parent
= allocated
= g_strndup(uri
, slash
- uri
);
436 ret
= change_directory(c
, parent
);
441 /* select the specified song */
443 i
= filelist_find_song(browser
.filelist
, song
);
447 list_window_set_cursor(browser
.lw
, i
);
449 /* finally, switch to the file screen */
450 screen_switch(&screen_browse
, c
);