1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2017 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 "save_playlist.h"
29 #include "mpdclient.h"
31 #include "screen_utils.h"
32 #include "screen_client.h"
35 #include <mpd/client.h>
42 static struct screen_browser browser
;
43 static char *current_path
;
46 screen_file_load_list(struct mpdclient
*c
, struct filelist
*filelist
)
48 struct mpd_connection
*connection
;
50 connection
= mpdclient_get_connection(c
);
51 if (connection
== NULL
)
54 mpd_send_list_meta(connection
, current_path
);
55 filelist_recv(filelist
, connection
);
57 if (mpdclient_finish_command(c
))
58 filelist_sort_dir_play(filelist
, compare_filelist_entry_path
);
62 screen_file_reload(struct mpdclient
*c
)
64 if (browser
.filelist
!= NULL
)
65 filelist_free(browser
.filelist
);
67 browser
.filelist
= filelist_new();
68 if (*current_path
!= 0)
69 /* add a dummy entry for ./.. */
70 filelist_append(browser
.filelist
, NULL
);
72 screen_file_load_list(c
, browser
.filelist
);
74 list_window_set_length(browser
.lw
,
75 filelist_length(browser
.filelist
));
79 * Change to the specified absolute directory.
82 change_directory(struct mpdclient
*c
, const char *new_path
)
85 current_path
= g_strdup(new_path
);
87 screen_file_reload(c
);
89 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
91 list_window_reset(browser
.lw
);
93 return browser
.filelist
!= NULL
;
97 * Change to the parent directory of the current directory.
100 change_to_parent(struct mpdclient
*c
)
102 char *parent
= g_path_get_dirname(current_path
);
103 if (strcmp(parent
, ".") == 0)
106 char *old_path
= current_path
;
109 bool success
= change_directory(c
, parent
);
113 ? filelist_find_directory(browser
.filelist
, old_path
)
117 if (success
&& idx
>= 0) {
118 /* set the cursor on the previous working directory */
119 list_window_set_cursor(browser
.lw
, idx
);
120 list_window_center(browser
.lw
, idx
);
127 * Change to the directory referred by the specified #filelist_entry
131 change_to_entry(struct mpdclient
*c
, const struct filelist_entry
*entry
)
133 assert(entry
!= NULL
);
135 if (entry
->entity
== NULL
)
136 return change_to_parent(c
);
137 else if (mpd_entity_get_type(entry
->entity
) == MPD_ENTITY_TYPE_DIRECTORY
)
138 return change_directory(c
, mpd_directory_get_path(mpd_entity_get_directory(entry
->entity
)));
144 screen_file_handle_enter(struct mpdclient
*c
)
146 const struct filelist_entry
*entry
= browser_get_selected_entry(&browser
);
151 return change_to_entry(c
, entry
);
155 handle_save(struct mpdclient
*c
)
157 struct list_window_range range
;
158 const char *defaultname
= NULL
;
160 list_window_get_range(browser
.lw
, &range
);
161 if (range
.start
== range
.end
)
164 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
165 struct filelist_entry
*entry
=
166 filelist_get(browser
.filelist
, i
);
167 if( entry
&& entry
->entity
) {
168 struct mpd_entity
*entity
= entry
->entity
;
169 if (mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_PLAYLIST
) {
170 const struct mpd_playlist
*playlist
=
171 mpd_entity_get_playlist(entity
);
172 defaultname
= mpd_playlist_get_path(playlist
);
177 char *defaultname_utf8
= NULL
;
179 defaultname_utf8
= utf8_to_locale(defaultname
);
180 playlist_save(c
, NULL
, defaultname_utf8
);
181 g_free(defaultname_utf8
);
185 handle_delete(struct mpdclient
*c
)
187 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
189 if (connection
== NULL
)
192 struct list_window_range range
;
193 list_window_get_range(browser
.lw
, &range
);
194 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
195 struct filelist_entry
*entry
=
196 filelist_get(browser
.filelist
, i
);
197 if( entry
==NULL
|| entry
->entity
==NULL
)
200 struct mpd_entity
*entity
= entry
->entity
;
202 if (mpd_entity_get_type(entity
) != MPD_ENTITY_TYPE_PLAYLIST
) {
203 /* translators: the "delete" command is only possible
204 for playlists; the user attempted to delete a song
205 or a directory or something else */
206 screen_status_printf(_("Deleting this item is not possible"));
211 const struct mpd_playlist
*playlist
= mpd_entity_get_playlist(entity
);
212 char *str
= utf8_to_locale(g_basename(mpd_playlist_get_path(playlist
)));
213 char *buf
= g_strdup_printf(_("Delete playlist %s?"), str
);
215 bool delete = screen_get_yesno(buf
, false);
219 /* translators: a dialog was aborted by the user */
220 screen_status_printf(_("Aborted"));
224 if (!mpd_run_rm(connection
, mpd_playlist_get_path(playlist
))) {
225 mpdclient_handle_error(c
);
229 c
->events
|= MPD_IDLE_STORED_PLAYLIST
;
231 /* translators: MPD deleted the playlist, as requested by the
233 screen_status_printf(_("Playlist deleted"));
238 screen_file_init(WINDOW
*w
, unsigned cols
, unsigned rows
)
240 current_path
= g_strdup("");
242 browser
.lw
= list_window_init(w
, cols
, rows
);
243 browser
.song_format
= options
.list_format
;
247 screen_file_resize(unsigned cols
, unsigned rows
)
249 list_window_resize(browser
.lw
, cols
, rows
);
253 screen_file_exit(void)
255 if (browser
.filelist
)
256 filelist_free(browser
.filelist
);
257 list_window_free(browser
.lw
);
259 g_free(current_path
);
263 screen_file_open(struct mpdclient
*c
)
265 screen_file_reload(c
);
266 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
270 screen_file_get_title(char *str
, size_t size
)
272 const char *path
= NULL
, *prev
= NULL
, *slash
= current_path
;
274 /* determine the last 2 parts of the path */
275 while ((slash
= strchr(slash
, '/')) != NULL
) {
281 /* fall back to full path */
284 char *path_locale
= utf8_to_locale(path
);
285 g_snprintf(str
, size
, "%s: %s",
286 /* translators: caption of the browser screen */
287 _("Browse"), path_locale
);
293 screen_file_paint(void)
295 screen_browser_paint(&browser
);
299 screen_file_update(struct mpdclient
*c
)
301 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
)) {
302 /* the db has changed -> update the filelist */
303 screen_file_reload(c
);
306 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
311 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
317 screen_file_cmd(struct mpdclient
*c
, command_t cmd
)
321 if (screen_file_handle_enter(c
)) {
328 case CMD_GO_ROOT_DIRECTORY
:
329 change_directory(c
, "");
332 case CMD_GO_PARENT_DIRECTORY
:
338 /* don't let browser_cmd() evaluate the locate command
339 - it's a no-op, and by the way, leads to a
340 segmentation fault in the current implementation */
343 case CMD_SCREEN_UPDATE
:
344 screen_file_reload(c
);
345 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
353 if (browser_cmd(&browser
, c
, cmd
)) {
354 if (screen_is_visible(&screen_browse
))
359 if (!mpdclient_is_connected(c
))
368 case CMD_SAVE_PLAYLIST
:
373 screen_database_update(c
, current_path
);
385 screen_file_mouse(struct mpdclient
*c
, int x
, int y
, mmask_t bstate
)
387 if (browser_mouse(&browser
, c
, x
, y
, bstate
)) {
388 if (screen_is_visible(&screen_browse
))
397 const struct screen_functions screen_browse
= {
398 .init
= screen_file_init
,
399 .exit
= screen_file_exit
,
400 .open
= screen_file_open
,
401 .resize
= screen_file_resize
,
402 .paint
= screen_file_paint
,
403 .update
= screen_file_update
,
404 .cmd
= screen_file_cmd
,
406 .mouse
= screen_file_mouse
,
408 .get_title
= screen_file_get_title
,
412 screen_file_goto_song(struct mpdclient
*c
, const struct mpd_song
*song
)
414 const char *uri
, *slash
, *parent
;
415 char *allocated
= NULL
;
417 assert(song
!= NULL
);
419 uri
= mpd_song_get_uri(song
);
421 if (strstr(uri
, "//") != NULL
)
425 /* determine the song's parent directory and go there */
427 slash
= strrchr(uri
, '/');
429 parent
= allocated
= g_strndup(uri
, slash
- uri
);
433 bool ret
= change_directory(c
, parent
);
438 /* select the specified song */
440 int i
= filelist_find_song(browser
.filelist
, song
);
444 list_window_set_cursor(browser
.lw
, i
);
446 /* finally, switch to the file screen */
447 screen_switch(&screen_browse
, c
);