1 /*
2 * $Id$
3 *
4 * (c) 2004 by Kalle Wallin <kaw@linux.se>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glib.h>
25 #include <ncurses.h>
27 #include "config.h"
28 #include "ncmpc.h"
29 #include "support.h"
30 #include "libmpdclient.h"
31 #include "mpc.h"
32 #include "command.h"
33 #include "screen.h"
34 #include "screen_utils.h"
35 #include "screen_play.h"
36 #include "screen_file.h"
38 #define BUFSIZE 1024
39 #define TITLESIZE 256
41 #define USE_OLD_LAYOUT
43 static list_window_t *lw;
44 static mpd_client_t *mpc = NULL;
46 static char *
47 list_callback(int index, int *highlight, void *data)
48 {
49 static char buf[BUFSIZE];
50 mpd_client_t *c = (mpd_client_t *) data;
51 filelist_entry_t *entry;
52 mpd_InfoEntity *entity;
54 *highlight = 0;
55 if( (entry=(filelist_entry_t *) g_list_nth_data(c->filelist, index))==NULL )
56 return NULL;
58 entity = entry->entity;
59 *highlight = entry->selected;
61 if( entity == NULL )
62 {
63 #ifdef USE_OLD_LAYOUT
64 return "[..]";
65 #else
66 return "d ..";
67 #endif
68 }
69 if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
70 {
71 mpd_Directory *dir = entity->info.directory;
72 char *dirname = utf8_to_locale(basename(dir->path));
74 #ifdef USE_OLD_LAYOUT
75 snprintf(buf, BUFSIZE, "[%s]", dirname);
76 #else
77 snprintf(buf, BUFSIZE, "d %s", dirname);
78 #endif
79 g_free(dirname);
80 return buf;
81 }
82 else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG )
83 {
84 mpd_Song *song = entity->info.song;
86 #ifdef USE_OLD_LAYOUT
87 return mpc_get_song_name(song);
88 #else
89 snprintf(buf, BUFSIZE, "m %s", mpc_get_song_name(song));
90 return buf;
91 #endif
93 }
94 else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
95 {
96 mpd_PlaylistFile *plf = entity->info.playlistFile;
97 char *filename = utf8_to_locale(basename(plf->path));
99 #ifdef USE_OLD_LAYOUT
100 snprintf(buf, BUFSIZE, "*%s*", filename);
101 #else
102 snprintf(buf, BUFSIZE, "p %s", filename);
103 #endif
104 g_free(filename);
105 return buf;
106 }
107 return "Error: Unknow entry!";
108 }
110 static int
111 change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
112 {
113 mpd_InfoEntity *entity = entry->entity;
115 if( entity==NULL )
116 {
117 char *parent = g_path_get_dirname(c->cwd);
119 if( strcmp(parent,".") == 0 )
120 {
121 parent[0] = '\0';
122 }
123 if( c->cwd )
124 g_free(c->cwd);
125 c->cwd = parent;
126 }
127 else
128 if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY)
129 {
130 mpd_Directory *dir = entity->info.directory;
131 if( c->cwd )
132 g_free(c->cwd);
133 c->cwd = g_strdup(dir->path);
134 }
135 else
136 return -1;
138 mpc_update_filelist(c);
139 list_window_reset(lw);
140 return 0;
141 }
143 static int
144 load_playlist(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
145 {
146 mpd_InfoEntity *entity = entry->entity;
147 mpd_PlaylistFile *plf = entity->info.playlistFile;
148 char *filename = utf8_to_locale(basename(plf->path));
150 mpd_sendLoadCommand(c->connection, plf->path);
151 mpd_finishCommand(c->connection);
153 screen_status_printf(_("Loading playlist %s..."), filename);
154 g_free(filename);
155 return 0;
156 }
158 static int
159 handle_delete(screen_t *screen, mpd_client_t *c)
160 {
161 filelist_entry_t *entry;
162 mpd_InfoEntity *entity;
163 mpd_PlaylistFile *plf;
164 char *str, buf[BUFSIZE];
165 int key;
167 entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
168 if( entry==NULL || entry->entity==NULL )
169 return -1;
171 entity = entry->entity;
173 if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
174 {
175 screen_status_printf(_("You can only delete playlists!"));
176 beep();
177 return -1;
178 }
180 plf = entity->info.playlistFile;
181 str = utf8_to_locale(basename(plf->path));
182 snprintf(buf, BUFSIZE, _("Delete playlist %s [y/n] ? "), str);
183 g_free(str);
184 key = tolower(screen_getch(screen->status_window.w, buf));
185 if( key==KEY_RESIZE )
186 screen_resize();
187 if( key!='y' )
188 {
189 screen_status_printf(_("Aborted!"));
190 return 0;
191 }
193 mpd_sendRmCommand(c->connection, plf->path);
194 mpd_finishCommand(c->connection);
195 if( mpc_error(c))
196 {
197 str = utf8_to_locale(mpc_error_str(c));
198 screen_status_printf("Error: %s", str);
199 g_free(str);
200 beep();
201 return -1;
202 }
203 screen_status_printf(_("Playlist deleted!"));
204 mpc_update_filelist(c);
205 list_window_check_selected(lw, c->filelist_length);
206 return 0;
207 }
210 static int
211 handle_play_cmd(screen_t *screen, mpd_client_t *c)
212 {
213 filelist_entry_t *entry;
214 mpd_InfoEntity *entity;
216 entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
217 if( entry==NULL )
218 return -1;
220 entity = entry->entity;
221 if( entity==NULL || entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
222 return change_directory(screen, c, entry);
223 else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
224 return load_playlist(screen, c, entry);
225 return -1;
226 }
228 static int
229 add_directory(mpd_client_t *c, char *dir)
230 {
231 mpd_InfoEntity *entity;
232 GList *subdir_list = NULL;
233 GList *list = NULL;
234 char *dirname;
236 dirname = utf8_to_locale(dir);
237 screen_status_printf(_("Adding directory %s...\n"), dirname);
238 doupdate();
239 g_free(dirname);
240 dirname = NULL;
242 mpd_sendLsInfoCommand(c->connection, dir);
243 mpd_sendCommandListBegin(c->connection);
244 while( (entity=mpd_getNextInfoEntity(c->connection)) )
245 {
246 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG )
247 {
248 mpd_Song *song = entity->info.song;
249 mpd_sendAddCommand(c->connection, song->file);
250 mpd_freeInfoEntity(entity);
251 }
252 else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
253 {
254 subdir_list = g_list_append(subdir_list, (gpointer) entity);
255 }
256 else
257 mpd_freeInfoEntity(entity);
258 }
259 mpd_sendCommandListEnd(c->connection);
260 mpd_finishCommand(c->connection);
262 list = g_list_first(subdir_list);
263 while( list!=NULL )
264 {
265 mpd_Directory *dir;
267 entity = list->data;
268 dir = entity->info.directory;
269 add_directory(c, dir->path);
270 mpd_freeInfoEntity(entity);
271 list->data=NULL;
272 list=list->next;
273 }
274 g_list_free(subdir_list);
275 return 0;
276 }
278 static int
279 handle_select(screen_t *screen, mpd_client_t *c)
280 {
281 filelist_entry_t *entry;
283 entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
284 if( entry==NULL || entry->entity==NULL)
285 return -1;
287 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
288 {
289 mpd_Directory *dir = entry->entity->info.directory;
290 add_directory(c, dir->path);
291 return 0;
292 }
294 if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG )
295 return -1;
297 entry->selected = !entry->selected;
299 if( entry->selected )
300 {
301 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG )
302 {
303 mpd_Song *song = entry->entity->info.song;
305 playlist_add_song(c, song);
307 screen_status_printf(_("Adding \'%s\' to playlist\n"),
308 mpc_get_song_name(song));
309 }
310 }
311 else
312 {
313 /* remove song from playlist */
314 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG )
315 {
316 mpd_Song *song = entry->entity->info.song;
318 if( song )
319 {
320 int index = mpc_playlist_get_song_index(c, song->file);
322 while( (index=mpc_playlist_get_song_index(c, song->file))>=0 )
323 playlist_delete_song(c, index);
324 }
325 }
326 }
327 return 0;
328 }
330 static void
331 file_init(WINDOW *w, int cols, int rows)
332 {
333 lw = list_window_init(w, cols, rows);
334 }
336 static void
337 file_resize(int cols, int rows)
338 {
339 lw->cols = cols;
340 lw->rows = rows;
341 }
343 static void
344 file_exit(void)
345 {
346 list_window_free(lw);
347 }
349 static void
350 file_open(screen_t *screen, mpd_client_t *c)
351 {
352 if( c->filelist == NULL )
353 {
354 mpc_update_filelist(c);
355 }
356 mpc = c;
357 }
359 static void
360 file_close(void)
361 {
362 }
364 static char *
365 file_title(char *str, size_t size)
366 {
367 char *tmp;
369 tmp = utf8_to_locale(basename(mpc->cwd));
370 snprintf(str, size, _("Browse: %s"), tmp);
371 g_free(tmp);
373 return str;
374 }
376 static void
377 file_paint(screen_t *screen, mpd_client_t *c)
378 {
379 lw->clear = 1;
381 list_window_paint(lw, list_callback, (void *) c);
382 wnoutrefresh(lw->w);
383 }
385 static void
386 file_update(screen_t *screen, mpd_client_t *c)
387 {
388 if( c->filelist_updated )
389 {
390 file_paint(screen, c);
391 c->filelist_updated = 0;
392 return;
393 }
394 list_window_paint(lw, list_callback, (void *) c);
395 wnoutrefresh(lw->w);
396 }
399 static int
400 file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
401 {
402 switch(cmd)
403 {
404 case CMD_PLAY:
405 handle_play_cmd(screen, c);
406 return 1;
407 case CMD_SELECT:
408 if( handle_select(screen, c) == 0 )
409 {
410 /* continue and select next item... */
411 cmd = CMD_LIST_NEXT;
412 }
413 break;
414 case CMD_DELETE:
415 handle_delete(screen, c);
416 break;
417 case CMD_SCREEN_UPDATE:
418 mpc_update_filelist(c);
419 list_window_check_selected(lw, c->filelist_length);
420 screen_status_printf(_("Screen updated!"));
421 return 1;
422 case CMD_LIST_FIND:
423 case CMD_LIST_RFIND:
424 case CMD_LIST_FIND_NEXT:
425 case CMD_LIST_RFIND_NEXT:
426 return screen_find(screen, c,
427 lw, c->filelist_length,
428 cmd, list_callback);
429 default:
430 break;
431 }
432 return list_window_cmd(lw, c->filelist_length, cmd);
433 }
436 list_window_t *
437 get_filelist_window()
438 {
439 return lw;
440 }
443 void
444 file_clear_highlights(mpd_client_t *c)
445 {
446 GList *list = g_list_first(c->filelist);
448 while( list )
449 {
450 filelist_entry_t *entry = list->data;
452 entry->selected = 0;
453 list = list->next;
454 }
455 }
457 void
458 file_set_highlight(mpd_client_t *c, mpd_Song *song, int highlight)
459 {
460 GList *list = g_list_first(c->filelist);
462 if( !song )
463 return;
465 while( list )
466 {
467 filelist_entry_t *entry = list->data;
468 mpd_InfoEntity *entity = entry->entity;
470 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
471 {
472 mpd_Song *song2 = entity->info.song;
474 if( strcmp(song->file, song2->file) == 0 )
475 {
476 entry->selected = highlight;
477 }
478 }
479 list = list->next;
480 }
481 }
483 screen_functions_t *
484 get_screen_file(void)
485 {
486 static screen_functions_t functions;
488 memset(&functions, 0, sizeof(screen_functions_t));
489 functions.init = file_init;
490 functions.exit = file_exit;
491 functions.open = file_open;
492 functions.close = file_close;
493 functions.resize = file_resize;
494 functions.paint = file_paint;
495 functions.update = file_update;
496 functions.cmd = file_cmd;
497 functions.get_lw = get_filelist_window;
498 functions.get_title = file_title;
500 return &functions;
501 }