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_status.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 (mpdclient_finish_command(c
))
67 filelist_sort_dir_play(filelist
, compare_filelist_entry_path
);
71 screen_file_reload(struct mpdclient
*c
)
73 if (browser
.filelist
!= NULL
)
74 filelist_free(browser
.filelist
);
76 browser
.filelist
= filelist_new();
77 if (*current_path
!= 0)
78 /* add a dummy entry for ./.. */
79 filelist_append(browser
.filelist
, NULL
);
81 screen_file_load_list(c
, browser
.filelist
);
83 list_window_set_length(browser
.lw
,
84 filelist_length(browser
.filelist
));
88 * Change to the specified absolute directory.
91 change_directory(struct mpdclient
*c
, const char *new_path
)
94 current_path
= g_strdup(new_path
);
96 screen_file_reload(c
);
98 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
100 list_window_reset(browser
.lw
);
102 return browser
.filelist
!= NULL
;
106 * Change to the parent directory of the current directory.
109 change_to_parent(struct mpdclient
*c
)
111 char *parent
= g_path_get_dirname(current_path
);
116 if (strcmp(parent
, ".") == 0)
119 old_path
= current_path
;
122 success
= change_directory(c
, parent
);
126 ? filelist_find_directory(browser
.filelist
, old_path
)
130 if (success
&& idx
>= 0) {
131 /* set the cursor on the previous working directory */
132 list_window_set_cursor(browser
.lw
, idx
);
133 list_window_center(browser
.lw
, idx
);
140 * Change to the directory referred by the specified #filelist_entry
144 change_to_entry(struct mpdclient
*c
, const struct filelist_entry
*entry
)
146 assert(entry
!= NULL
);
148 if (entry
->entity
== NULL
)
149 return change_to_parent(c
);
150 else if (mpd_entity_get_type(entry
->entity
) == MPD_ENTITY_TYPE_DIRECTORY
)
151 return change_directory(c
, mpd_directory_get_path(mpd_entity_get_directory(entry
->entity
)));
157 screen_file_handle_enter(struct mpdclient
*c
)
159 const struct filelist_entry
*entry
= browser_get_selected_entry(&browser
);
164 return change_to_entry(c
, entry
);
168 handle_save(struct mpdclient
*c
)
170 struct list_window_range range
;
171 const char *defaultname
= NULL
;
172 char *defaultname_utf8
= NULL
;
174 list_window_get_range(browser
.lw
, &range
);
175 if (range
.start
== range
.end
)
178 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
179 struct filelist_entry
*entry
=
180 filelist_get(browser
.filelist
, i
);
181 if( entry
&& entry
->entity
) {
182 struct mpd_entity
*entity
= entry
->entity
;
183 if (mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_PLAYLIST
) {
184 const struct mpd_playlist
*playlist
=
185 mpd_entity_get_playlist(entity
);
186 defaultname
= mpd_playlist_get_path(playlist
);
192 defaultname_utf8
= utf8_to_locale(defaultname
);
193 playlist_save(c
, NULL
, defaultname_utf8
);
194 g_free(defaultname_utf8
);
198 handle_delete(struct mpdclient
*c
)
200 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
201 struct list_window_range range
;
202 struct mpd_entity
*entity
;
203 const struct mpd_playlist
*playlist
;
206 if (connection
== NULL
)
209 list_window_get_range(browser
.lw
, &range
);
210 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
211 struct filelist_entry
*entry
=
212 filelist_get(browser
.filelist
, i
);
213 if( entry
==NULL
|| entry
->entity
==NULL
)
216 entity
= entry
->entity
;
218 if (mpd_entity_get_type(entity
) != MPD_ENTITY_TYPE_PLAYLIST
) {
219 /* translators: the "delete" command is only possible
220 for playlists; the user attempted to delete a song
221 or a directory or something else */
222 screen_status_printf(_("Deleting this item is not possible"));
227 playlist
= mpd_entity_get_playlist(entity
);
228 str
= utf8_to_locale(g_basename(mpd_playlist_get_path(playlist
)));
229 buf
= g_strdup_printf(_("Delete playlist %s [%s/%s] ? "), str
, YES
, NO
);
231 bool delete = screen_get_yesno(buf
, false);
235 /* translators: a dialog was aborted by the user */
236 screen_status_printf(_("Aborted"));
240 if (!mpd_run_rm(connection
, mpd_playlist_get_path(playlist
))) {
241 mpdclient_handle_error(c
);
245 c
->events
|= MPD_IDLE_STORED_PLAYLIST
;
247 /* translators: MPD deleted the playlist, as requested by the
249 screen_status_printf(_("Playlist deleted"));
254 screen_file_init(WINDOW
*w
, int cols
, int rows
)
256 current_path
= g_strdup("");
258 browser
.lw
= list_window_init(w
, cols
, rows
);
262 screen_file_resize(int cols
, int rows
)
264 list_window_resize(browser
.lw
, cols
, rows
);
268 screen_file_exit(void)
270 if (browser
.filelist
)
271 filelist_free(browser
.filelist
);
272 list_window_free(browser
.lw
);
274 g_free(current_path
);
278 screen_file_open(struct mpdclient
*c
)
280 screen_file_reload(c
);
281 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
285 screen_file_get_title(char *str
, size_t size
)
287 const char *path
= NULL
, *prev
= NULL
, *slash
= current_path
;
290 /* determine the last 2 parts of the path */
291 while ((slash
= strchr(slash
, '/')) != NULL
) {
297 /* fall back to full path */
300 path_locale
= utf8_to_locale(path
);
301 g_snprintf(str
, size
, "%s: %s",
302 /* translators: caption of the browser screen */
303 _("Browse"), path_locale
);
309 screen_file_paint(void)
311 screen_browser_paint(&browser
);
315 screen_file_update(struct mpdclient
*c
)
317 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
)) {
318 /* the db has changed -> update the filelist */
319 screen_file_reload(c
);
322 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
327 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
328 screen_file_repaint();
333 screen_file_cmd(struct mpdclient
*c
, command_t cmd
)
337 if (screen_file_handle_enter(c
)) {
338 screen_file_repaint();
344 case CMD_GO_ROOT_DIRECTORY
:
345 change_directory(c
, "");
346 screen_file_repaint();
348 case CMD_GO_PARENT_DIRECTORY
:
350 screen_file_repaint();
354 /* don't let browser_cmd() evaluate the locate command
355 - it's a no-op, and by the way, leads to a
356 segmentation fault in the current implementation */
359 case CMD_SCREEN_UPDATE
:
360 screen_file_reload(c
);
361 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
362 screen_file_repaint();
369 if (browser_cmd(&browser
, c
, cmd
)) {
370 if (screen_is_visible(&screen_browse
))
371 screen_file_repaint();
375 if (!mpdclient_is_connected(c
))
381 screen_file_repaint();
384 case CMD_SAVE_PLAYLIST
:
389 screen_database_update(c
, current_path
);
399 const struct screen_functions screen_browse
= {
400 .init
= screen_file_init
,
401 .exit
= screen_file_exit
,
402 .open
= screen_file_open
,
403 .resize
= screen_file_resize
,
404 .paint
= screen_file_paint
,
405 .update
= screen_file_update
,
406 .cmd
= screen_file_cmd
,
407 .get_title
= screen_file_get_title
,
411 screen_file_goto_song(struct mpdclient
*c
, const struct mpd_song
*song
)
413 const char *uri
, *slash
, *parent
;
414 char *allocated
= NULL
;
418 assert(song
!= NULL
);
420 uri
= mpd_song_get_uri(song
);
422 if (strstr(uri
, "//") != NULL
)
426 /* determine the song's parent directory and go there */
428 slash
= strrchr(uri
, '/');
430 parent
= allocated
= g_strndup(uri
, slash
- uri
);
434 ret
= change_directory(c
, parent
);
439 /* select the specified song */
441 i
= filelist_find_song(browser
.filelist
, song
);
445 list_window_set_cursor(browser
.lw
, i
);
447 /* finally, switch to the file screen */
448 screen_switch(&screen_browse
, c
);