Code

Added the strscroll function
[ncmpc.git] / src / screen_file.c
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!";
110 static int
111 change_directory(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
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;
137   
138   mpc_update_filelist(c);
139   list_window_reset(lw);
140   return 0;
143 static int
144 load_playlist(screen_t *screen, mpd_client_t *c, filelist_entry_t *entry)
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;
158 static int 
159 handle_delete(screen_t *screen, mpd_client_t *c)
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;
210 static int
211 handle_play_cmd(screen_t *screen, mpd_client_t *c)
213   filelist_entry_t *entry;
214   mpd_InfoEntity *entity;
215   
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;
228 static int
229 add_directory(mpd_client_t *c, char *dir)
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);
261   
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;
278 static int
279 handle_select(screen_t *screen, mpd_client_t *c)
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);
321               
322               while( (index=mpc_playlist_get_song_index(c, song->file))>=0 )
323                 playlist_delete_song(c, index);
324             }
325         }
326     }
327   return 0;
330 static void
331 file_init(WINDOW *w, int cols, int rows)
333   lw = list_window_init(w, cols, rows);
336 static void
337 file_resize(int cols, int rows)
339   lw->cols = cols;
340   lw->rows = rows;
343 static void
344 file_exit(void)
346   list_window_free(lw);
349 static void 
350 file_open(screen_t *screen, mpd_client_t *c)
352   if( c->filelist == NULL )
353     {
354       mpc_update_filelist(c);
355     }
356   mpc = c;
359 static void
360 file_close(void)
364 static char *
365 file_title(char *str, size_t size)
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;
376 static void 
377 file_paint(screen_t *screen, mpd_client_t *c)
379   lw->clear = 1;
380   
381   list_window_paint(lw, list_callback, (void *) c);
382   wnoutrefresh(lw->w);
385 static void 
386 file_update(screen_t *screen, mpd_client_t *c)
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);
399 static int 
400 file_cmd(screen_t *screen, mpd_client_t *c, command_t cmd)
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);
436 list_window_t *
437 get_filelist_window()
439   return lw;
443 void
444 file_clear_highlights(mpd_client_t *c)
446   GList *list = g_list_first(c->filelist);
447   
448   while( list )
449     {
450       filelist_entry_t *entry = list->data;
452       entry->selected = 0;
453       list = list->next;
454     }
457 void
458 file_set_highlight(mpd_client_t *c, mpd_Song *song, int highlight)
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     }
483 screen_functions_t *
484 get_screen_file(void)
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;