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