Code

Documentation update.
[ncmpc.git] / screen_file.c
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!";
107 static int
108 change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
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;
134   
135   mpc_update_filelist(c);
136   list_window_reset(lw);
137   return 0;
140 static int
141 load_playlist(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
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;
155 static int 
156 handle_delete(screen_t *screen, mpd_client_t *c)
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;
207 static int
208 handle_play_cmd(screen_t *screen, mpd_client_t *c)
210   filelist_entry_t *entry;
211   mpd_InfoEntity *entity;
212   
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;
225 static int
226 add_directory(mpd_client_t *c, char *dir)
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);
258   
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;
275 static int
276 handle_select(screen_t *screen, mpd_client_t *c)
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);
318               
319               while( (index=mpc_playlist_get_song_index(c, song->file))>=0 )
320                 playlist_delete_song(c, index);
321             }
322         }
323     }
324   return 0;
327 static void
328 file_init(WINDOW *w, int cols, int rows)
330   lw = list_window_init(w, cols, rows);
333 static void
334 file_resize(int cols, int rows)
336   lw->cols = cols;
337   lw->rows = rows;
340 static void
341 file_exit(void)
343   list_window_free(lw);
346 static void 
347 file_open(screen_t *screen, mpd_client_t *c)
349   if( c->filelist == NULL )
350     {
351       mpc_update_filelist(c);
352     }
353   mpc = c;
356 static void
357 file_close(void)
361 static char *
362 file_title(void)
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;
377 static void 
378 file_paint(screen_t *screen, mpd_client_t *c)
380   lw->clear = 1;
381   
382   list_window_paint(lw, list_callback, (void *) c);
383   wnoutrefresh(lw->w);
386 static void 
387 file_update(screen_t *screen, mpd_client_t *c)
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);
400 static int 
401 file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
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);
437 list_window_t *
438 get_filelist_window()
440   return lw;
444 void
445 file_clear_highlights(mpd_client_t *c)
447   GList *list = g_list_first(c->filelist);
448   
449   while( list )
450     {
451       filelist_entry_t *entry = list->data;
453       entry->selected = 0;
454       list = list->next;
455     }
458 void
459 file_set_highlight(mpd_client_t *c, mpd_Song *song, int highlight)
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     }
484 screen_functions_t *
485 get_screen_file(void)
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;