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"
35 #include <mpd/client.h>
42 static struct screen_browser browser
;
43 static char *current_path
;
46 screen_file_paint(void);
49 screen_file_repaint(void)
52 wrefresh(browser
.lw
->w
);
56 screen_file_load_list(struct mpdclient
*c
, struct filelist
*filelist
)
58 struct mpd_connection
*connection
;
60 connection
= mpdclient_get_connection(c
);
61 if (connection
== NULL
)
64 mpd_send_list_meta(connection
, current_path
);
65 filelist_recv(filelist
, connection
);
67 if (mpdclient_finish_command(c
))
68 filelist_sort_dir_play(filelist
, compare_filelist_entry_path
);
72 screen_file_reload(struct mpdclient
*c
)
74 if (browser
.filelist
!= NULL
)
75 filelist_free(browser
.filelist
);
77 browser
.filelist
= filelist_new();
78 if (*current_path
!= 0)
79 /* add a dummy entry for ./.. */
80 filelist_append(browser
.filelist
, NULL
);
82 screen_file_load_list(c
, browser
.filelist
);
84 list_window_set_length(browser
.lw
,
85 filelist_length(browser
.filelist
));
89 * Change to the specified absolute directory.
92 change_directory(struct mpdclient
*c
, const char *new_path
)
95 current_path
= g_strdup(new_path
);
97 screen_file_reload(c
);
99 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
101 list_window_reset(browser
.lw
);
103 return browser
.filelist
!= NULL
;
107 * Change to the parent directory of the current directory.
110 change_to_parent(struct mpdclient
*c
)
112 char *parent
= g_path_get_dirname(current_path
);
113 if (strcmp(parent
, ".") == 0)
116 char *old_path
= current_path
;
119 bool success
= change_directory(c
, parent
);
123 ? filelist_find_directory(browser
.filelist
, old_path
)
127 if (success
&& idx
>= 0) {
128 /* set the cursor on the previous working directory */
129 list_window_set_cursor(browser
.lw
, idx
);
130 list_window_center(browser
.lw
, idx
);
137 * Change to the directory referred by the specified #filelist_entry
141 change_to_entry(struct mpdclient
*c
, const struct filelist_entry
*entry
)
143 assert(entry
!= NULL
);
145 if (entry
->entity
== NULL
)
146 return change_to_parent(c
);
147 else if (mpd_entity_get_type(entry
->entity
) == MPD_ENTITY_TYPE_DIRECTORY
)
148 return change_directory(c
, mpd_directory_get_path(mpd_entity_get_directory(entry
->entity
)));
154 screen_file_handle_enter(struct mpdclient
*c
)
156 const struct filelist_entry
*entry
= browser_get_selected_entry(&browser
);
161 return change_to_entry(c
, entry
);
165 handle_save(struct mpdclient
*c
)
167 struct list_window_range range
;
168 const char *defaultname
= NULL
;
170 list_window_get_range(browser
.lw
, &range
);
171 if (range
.start
== range
.end
)
174 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
175 struct filelist_entry
*entry
=
176 filelist_get(browser
.filelist
, i
);
177 if( entry
&& entry
->entity
) {
178 struct mpd_entity
*entity
= entry
->entity
;
179 if (mpd_entity_get_type(entity
) == MPD_ENTITY_TYPE_PLAYLIST
) {
180 const struct mpd_playlist
*playlist
=
181 mpd_entity_get_playlist(entity
);
182 defaultname
= mpd_playlist_get_path(playlist
);
187 char *defaultname_utf8
= NULL
;
189 defaultname_utf8
= utf8_to_locale(defaultname
);
190 playlist_save(c
, NULL
, defaultname_utf8
);
191 g_free(defaultname_utf8
);
195 handle_delete(struct mpdclient
*c
)
197 struct mpd_connection
*connection
= mpdclient_get_connection(c
);
199 if (connection
== NULL
)
202 struct list_window_range range
;
203 list_window_get_range(browser
.lw
, &range
);
204 for (unsigned i
= range
.start
; i
< range
.end
; ++i
) {
205 struct filelist_entry
*entry
=
206 filelist_get(browser
.filelist
, i
);
207 if( entry
==NULL
|| entry
->entity
==NULL
)
210 struct mpd_entity
*entity
= entry
->entity
;
212 if (mpd_entity_get_type(entity
) != MPD_ENTITY_TYPE_PLAYLIST
) {
213 /* translators: the "delete" command is only possible
214 for playlists; the user attempted to delete a song
215 or a directory or something else */
216 screen_status_printf(_("Deleting this item is not possible"));
221 const struct mpd_playlist
*playlist
= mpd_entity_get_playlist(entity
);
222 char *str
= utf8_to_locale(g_basename(mpd_playlist_get_path(playlist
)));
223 char *buf
= g_strdup_printf(_("Delete playlist %s [%s/%s] ? "), str
, YES
, NO
);
225 bool delete = screen_get_yesno(buf
, false);
229 /* translators: a dialog was aborted by the user */
230 screen_status_printf(_("Aborted"));
234 if (!mpd_run_rm(connection
, mpd_playlist_get_path(playlist
))) {
235 mpdclient_handle_error(c
);
239 c
->events
|= MPD_IDLE_STORED_PLAYLIST
;
241 /* translators: MPD deleted the playlist, as requested by the
243 screen_status_printf(_("Playlist deleted"));
248 screen_file_init(WINDOW
*w
, int cols
, int rows
)
250 current_path
= g_strdup("");
252 browser
.lw
= list_window_init(w
, cols
, rows
);
253 browser
.song_format
= options
.list_format
;
257 screen_file_resize(int cols
, int rows
)
259 list_window_resize(browser
.lw
, cols
, rows
);
263 screen_file_exit(void)
265 if (browser
.filelist
)
266 filelist_free(browser
.filelist
);
267 list_window_free(browser
.lw
);
269 g_free(current_path
);
273 screen_file_open(struct mpdclient
*c
)
275 screen_file_reload(c
);
276 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
280 screen_file_get_title(char *str
, size_t size
)
282 const char *path
= NULL
, *prev
= NULL
, *slash
= current_path
;
284 /* determine the last 2 parts of the path */
285 while ((slash
= strchr(slash
, '/')) != NULL
) {
291 /* fall back to full path */
294 char *path_locale
= utf8_to_locale(path
);
295 g_snprintf(str
, size
, "%s: %s",
296 /* translators: caption of the browser screen */
297 _("Browse"), path_locale
);
303 screen_file_paint(void)
305 screen_browser_paint(&browser
);
309 screen_file_update(struct mpdclient
*c
)
311 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
)) {
312 /* the db has changed -> update the filelist */
313 screen_file_reload(c
);
316 if (c
->events
& (MPD_IDLE_DATABASE
| MPD_IDLE_STORED_PLAYLIST
321 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
322 screen_file_repaint();
327 screen_file_cmd(struct mpdclient
*c
, command_t cmd
)
331 if (screen_file_handle_enter(c
)) {
332 screen_file_repaint();
338 case CMD_GO_ROOT_DIRECTORY
:
339 change_directory(c
, "");
340 screen_file_repaint();
342 case CMD_GO_PARENT_DIRECTORY
:
344 screen_file_repaint();
348 /* don't let browser_cmd() evaluate the locate command
349 - it's a no-op, and by the way, leads to a
350 segmentation fault in the current implementation */
353 case CMD_SCREEN_UPDATE
:
354 screen_file_reload(c
);
355 screen_browser_sync_highlights(browser
.filelist
, &c
->playlist
);
356 screen_file_repaint();
363 if (browser_cmd(&browser
, c
, cmd
)) {
364 if (screen_is_visible(&screen_browse
))
365 screen_file_repaint();
369 if (!mpdclient_is_connected(c
))
375 screen_file_repaint();
378 case CMD_SAVE_PLAYLIST
:
383 screen_database_update(c
, current_path
);
393 const struct screen_functions screen_browse
= {
394 .init
= screen_file_init
,
395 .exit
= screen_file_exit
,
396 .open
= screen_file_open
,
397 .resize
= screen_file_resize
,
398 .paint
= screen_file_paint
,
399 .update
= screen_file_update
,
400 .cmd
= screen_file_cmd
,
401 .get_title
= screen_file_get_title
,
405 screen_file_goto_song(struct mpdclient
*c
, const struct mpd_song
*song
)
407 const char *uri
, *slash
, *parent
;
408 char *allocated
= NULL
;
410 assert(song
!= NULL
);
412 uri
= mpd_song_get_uri(song
);
414 if (strstr(uri
, "//") != NULL
)
418 /* determine the song's parent directory and go there */
420 slash
= strrchr(uri
, '/');
422 parent
= allocated
= g_strndup(uri
, slash
- uri
);
426 bool ret
= change_directory(c
, parent
);
431 /* select the specified song */
433 int i
= filelist_find_song(browser
.filelist
, song
);
437 list_window_set_cursor(browser
.lw
, i
);
439 /* finally, switch to the file screen */
440 screen_switch(&screen_browse
, c
);