Code

f86e8df95d16f2ee6c20663b4673d3b6668e2c77
[ncmpc.git] / src / 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 "ncmpc.h"
27 #include "support.h"
28 #include "libmpdclient.h"
29 #include "mpc.h"
30 #include "command.h"
31 #include "screen.h"
32 #include "screen_utils.h"
33 #include "screen_play.h"
34 #include "screen_file.h"
36 #define BUFSIZE 1024
37 #define TITLESIZE 256
39 #define USE_OLD_LAYOUT
41 static list_window_t *lw;
42 static mpd_client_t *mpc = NULL;
44 static char *
45 list_callback(int index, int *highlight, void *data)
46 {
47   static char buf[BUFSIZE];
48   mpd_client_t *c = (mpd_client_t *) data;
49   filelist_entry_t *entry;
50   mpd_InfoEntity *entity;
52   *highlight = 0;
53   if( (entry=(filelist_entry_t *) g_list_nth_data(c->filelist, index))==NULL )
54     return NULL;
56   entity = entry->entity;
57   *highlight = entry->selected;
59   if( entity == NULL )
60     {
61 #ifdef USE_OLD_LAYOUT
62       return "[..]";
63 #else
64       return "d ..";
65 #endif
66     }
67   if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) 
68     {
69       mpd_Directory *dir = entity->info.directory;
70       char *dirname = utf8_to_locale(basename(dir->path));
72 #ifdef USE_OLD_LAYOUT
73       snprintf(buf, BUFSIZE, "[%s]", dirname);
74 #else
75       snprintf(buf, BUFSIZE, "d %s", dirname);
76 #endif
77       g_free(dirname);
78       return buf;
79     }
80   else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG )
81     {
82       mpd_Song *song = entity->info.song;
84 #ifdef USE_OLD_LAYOUT      
85       return mpc_get_song_name(song);
86 #else
87       snprintf(buf, BUFSIZE, "m %s", mpc_get_song_name(song));
88       return buf;
89 #endif
91     }
92   else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
93     {
94       mpd_PlaylistFile *plf = entity->info.playlistFile;
95       char *filename = utf8_to_locale(basename(plf->path));
97 #ifdef USE_OLD_LAYOUT      
98       snprintf(buf, BUFSIZE, "*%s*", filename);
99 #else      
100       snprintf(buf, BUFSIZE, "p %s", filename);
101 #endif
102       g_free(filename);
103       return buf;
104     }
105   return "Error: Unknow entry!";
108 static int
109 change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
111   mpd_InfoEntity *entity = entry->entity;
113   if( entity==NULL )
114     {
115       char *parent = g_path_get_dirname(c->cwd);
117       if( strcmp(parent,".") == 0 )
118         {
119           parent[0] = '\0';
120         }
121       if( c->cwd )
122         g_free(c->cwd);
123       c->cwd = parent;
124     }
125   else
126     if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY)
127       {
128         mpd_Directory *dir = entity->info.directory;
129         if( c->cwd )
130           g_free(c->cwd);
131         c->cwd = g_strdup(dir->path);      
132       }
133     else
134       return -1;
135   
136   mpc_update_filelist(c);
137   list_window_reset(lw);
138   return 0;
141 static int
142 load_playlist(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
144   mpd_InfoEntity *entity = entry->entity;
145   mpd_PlaylistFile *plf = entity->info.playlistFile;
146   char *filename = utf8_to_locale(basename(plf->path));
148   mpd_sendLoadCommand(c->connection, plf->path);
149   mpd_finishCommand(c->connection);
151   screen_status_printf(_("Loading playlist %s..."), filename);
152   g_free(filename);
153   return 0;
156 static int 
157 handle_delete(screen_t *screen, mpd_client_t *c)
159   filelist_entry_t *entry;
160   mpd_InfoEntity *entity;
161   mpd_PlaylistFile *plf;
162   char *str, buf[BUFSIZE];
163   int key;
165   entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
166   if( entry==NULL || entry->entity==NULL )
167     return -1;
169   entity = entry->entity;
171   if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
172     {
173       screen_status_printf(_("You can only delete playlists!"));
174       beep();
175       return -1;
176     }
178   plf = entity->info.playlistFile;
179   str = utf8_to_locale(basename(plf->path));
180   snprintf(buf, BUFSIZE, _("Delete playlist %s [y/n] ? "), str);
181   g_free(str);  
182   key = tolower(screen_getch(screen->status_window.w, buf));
183   if( key==KEY_RESIZE )
184     screen_resize();
185   if( key!='y' )
186     {
187       screen_status_printf(_("Aborted!"));
188       return 0;
189     }
191   mpd_sendRmCommand(c->connection, plf->path);
192   mpd_finishCommand(c->connection);
193   if( mpc_error(c))
194     {
195       str = utf8_to_locale(mpc_error_str(c));
196       screen_status_printf("Error: %s", str);
197       g_free(str);
198       beep();
199       return -1;
200     }
201   screen_status_printf(_("Playlist deleted!"));
202   mpc_update_filelist(c);
203   list_window_check_selected(lw, c->filelist_length);
204   return 0;
208 static int
209 handle_play_cmd(screen_t *screen, mpd_client_t *c)
211   filelist_entry_t *entry;
212   mpd_InfoEntity *entity;
213   
214   entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
215   if( entry==NULL )
216     return -1;
218   entity = entry->entity;
219   if( entity==NULL || entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
220     return change_directory(screen, c, entry);
221   else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE )
222     return load_playlist(screen, c, entry);
223   return -1;
226 static int
227 add_directory(mpd_client_t *c, char *dir)
229   mpd_InfoEntity *entity;
230   GList *subdir_list = NULL;
231   GList *list = NULL;
232   char *dirname;
234   dirname = utf8_to_locale(dir);
235   screen_status_printf(_("Adding directory %s...\n"), dirname);
236   doupdate(); 
237   g_free(dirname);
238   dirname = NULL;
240   mpd_sendLsInfoCommand(c->connection, dir);
241   mpd_sendCommandListBegin(c->connection);
242   while( (entity=mpd_getNextInfoEntity(c->connection)) )
243     {
244       if( entity->type==MPD_INFO_ENTITY_TYPE_SONG )
245         {
246           mpd_Song *song = entity->info.song;
247           mpd_sendAddCommand(c->connection, song->file);
248           mpd_freeInfoEntity(entity);
249         }
250       else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
251         {
252           subdir_list = g_list_append(subdir_list, (gpointer) entity); 
253         }
254       else
255         mpd_freeInfoEntity(entity);
256     }
257   mpd_sendCommandListEnd(c->connection);
258   mpd_finishCommand(c->connection);
259   
260   list = g_list_first(subdir_list);
261   while( list!=NULL )
262     {
263       mpd_Directory *dir;
265       entity = list->data;
266       dir = entity->info.directory;
267       add_directory(c, dir->path);
268       mpd_freeInfoEntity(entity);
269       list->data=NULL;
270       list=list->next;
271     }
272   g_list_free(subdir_list);
273   return 0;
276 static int
277 handle_select(screen_t *screen, mpd_client_t *c)
279   filelist_entry_t *entry;
281   entry = ( filelist_entry_t *) g_list_nth_data(c->filelist, lw->selected);
282   if( entry==NULL || entry->entity==NULL)
283     return -1;
285   if( entry->entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY )
286     {
287       mpd_Directory *dir = entry->entity->info.directory;
288       add_directory(c, dir->path);
289       return 0;
290     }
292   if( entry->entity->type!=MPD_INFO_ENTITY_TYPE_SONG )
293     return -1; 
295   entry->selected = !entry->selected;
297   if( entry->selected )
298     {
299       if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG )
300         {
301           mpd_Song *song = entry->entity->info.song;
303           playlist_add_song(c, song);
305           screen_status_printf(_("Adding \'%s\' to playlist\n"), 
306                                mpc_get_song_name(song));
307         }
308     }
309   else
310     {
311       /* remove song from playlist */
312       if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG )
313         {
314           mpd_Song *song = entry->entity->info.song;
316           if( song )
317             {
318               int index = mpc_playlist_get_song_index(c, song->file);
319               
320               while( (index=mpc_playlist_get_song_index(c, song->file))>=0 )
321                 playlist_delete_song(c, index);
322             }
323         }
324     }
325   return 0;
328 static void
329 file_init(WINDOW *w, int cols, int rows)
331   lw = list_window_init(w, cols, rows);
334 static void
335 file_resize(int cols, int rows)
337   lw->cols = cols;
338   lw->rows = rows;
341 static void
342 file_exit(void)
344   list_window_free(lw);
347 static void 
348 file_open(screen_t *screen, mpd_client_t *c)
350   if( c->filelist == NULL )
351     {
352       mpc_update_filelist(c);
353     }
354   mpc = c;
357 static void
358 file_close(void)
362 static char *
363 file_title(void)
365   static char buf[TITLESIZE];
366   char *tmp;
368   tmp = utf8_to_locale(basename(mpc->cwd));
369   snprintf(buf, TITLESIZE, _("Browse: %s"), tmp);
370   g_free(tmp);
372   return buf;
375 static void 
376 file_paint(screen_t *screen, mpd_client_t *c)
378   lw->clear = 1;
379   
380   list_window_paint(lw, list_callback, (void *) c);
381   wnoutrefresh(lw->w);
384 static void 
385 file_update(screen_t *screen, mpd_client_t *c)
387   if( c->filelist_updated )
388     {
389       file_paint(screen, c);
390       c->filelist_updated = 0;
391       return;
392     }
393   list_window_paint(lw, list_callback, (void *) c);
394   wnoutrefresh(lw->w);
398 static int 
399 file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
401   switch(cmd)
402     {
403     case CMD_PLAY:
404       handle_play_cmd(screen, c);
405       return 1;
406     case CMD_SELECT:
407       if( handle_select(screen, c) == 0 )
408         {
409           /* continue and select next item... */
410           cmd = CMD_LIST_NEXT;
411         }
412       break;
413     case CMD_DELETE:
414       handle_delete(screen, c);
415       break;
416     case CMD_SCREEN_UPDATE:
417       mpc_update_filelist(c);
418       list_window_check_selected(lw, c->filelist_length);
419       screen_status_printf(_("Screen updated!"));
420       return 1;
421     case CMD_LIST_FIND:
422     case CMD_LIST_RFIND:
423     case CMD_LIST_FIND_NEXT:
424     case CMD_LIST_RFIND_NEXT:
425       return screen_find(screen, c, 
426                          lw, c->filelist_length,
427                          cmd, list_callback);
428     default:
429       break;
430     }
431   return list_window_cmd(lw, c->filelist_length, cmd);
435 list_window_t *
436 get_filelist_window()
438   return lw;
442 void
443 file_clear_highlights(mpd_client_t *c)
445   GList *list = g_list_first(c->filelist);
446   
447   while( list )
448     {
449       filelist_entry_t *entry = list->data;
451       entry->selected = 0;
452       list = list->next;
453     }
456 void
457 file_set_highlight(mpd_client_t *c, mpd_Song *song, int highlight)
459   GList *list = g_list_first(c->filelist);
461   if( !song )
462     return;
464   while( list )
465     {
466       filelist_entry_t *entry = list->data;
467       mpd_InfoEntity *entity  = entry->entity;
469       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
470         {
471           mpd_Song *song2 = entity->info.song;
473           if( strcmp(song->file, song2->file) == 0 )
474             {
475               entry->selected = highlight;
476             }
477         }
478       list = list->next;
479     }
482 screen_functions_t *
483 get_screen_file(void)
485   static screen_functions_t functions;
487   memset(&functions, 0, sizeof(screen_functions_t));
488   functions.init   = file_init;
489   functions.exit   = file_exit;
490   functions.open   = file_open;
491   functions.close  = file_close;
492   functions.resize = file_resize;
493   functions.paint  = file_paint;
494   functions.update = file_update;
495   functions.cmd    = file_cmd;
496   functions.get_lw = get_filelist_window;
497   functions.get_title = file_title;
499   return &functions;