Code

828cbe21ca6c2749ffda7b909aeda3002e38d6ca
[ncmpc.git] / src / screen_browser.c
1 /*
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  * Copyright (C) 2008 Max Kellermann <max@duempel.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
22 #include "screen_browser.h"
23 #include "ncmpc.h"
24 #include "options.h"
25 #include "support.h"
26 #include "strfsong.h"
27 #include "screen_utils.h"
28 #include "gcc.h"
30 #include <string.h>
32 #define USE_OLD_LAYOUT
33 #undef  USE_OLD_ADD
35 #define BUFSIZE 1024
37 #define HIGHLIGHT  (0x01)
39 /* clear the highlight flag for all items in the filelist */
40 static void
41 clear_highlights(mpdclient_filelist_t *fl)
42 {
43         GList *list = g_list_first(fl->list);
45         while( list ) {
46                 filelist_entry_t *entry = list->data;
48                 entry->flags &= ~HIGHLIGHT;
49                 list = list->next;
50         }
51 }
53 /* change the highlight flag for a song */
54 static void
55 set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight)
56 {
57         struct filelist_entry *entry = mpdclient_filelist_find_song(fl, song);
58         mpd_InfoEntity *entity;
60         if (entry == NULL)
61                 return;
63         entity = entry->entity;
64         if (highlight)
65                 entry->flags |= HIGHLIGHT;
66         else
67                 entry->flags &= ~HIGHLIGHT;
68 }
70 /* sync highlight flags with playlist */
71 void
72 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
73 {
74         GList *list = g_list_first(fl->list);
76         while(list) {
77                 filelist_entry_t *entry = list->data;
78                 mpd_InfoEntity *entity = entry->entity;
80                 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
81                         mpd_Song *song = entity->info.song;
83                         if( playlist_get_index_from_file(c, song->file) >= 0 )
84                                 entry->flags |= HIGHLIGHT;
85                         else
86                                 entry->flags &= ~HIGHLIGHT;
87                 }
88                 list=list->next;
89         }
90 }
92 /* the playlist have been updated -> fix highlights */
93 void
94 browser_playlist_changed(struct screen_browser *browser, mpdclient_t *c,
95                          int event, gpointer data)
96 {
97         if (browser->filelist == NULL)
98                 return;
100         D("screen_file.c> playlist_callback() [%d]\n", event);
101         switch(event) {
102         case PLAYLIST_EVENT_CLEAR:
103                 clear_highlights(browser->filelist);
104                 break;
105         case PLAYLIST_EVENT_ADD:
106                 set_highlight(browser->filelist, (mpd_Song *) data, 1);
107                 break;
108         case PLAYLIST_EVENT_DELETE:
109                 set_highlight(browser->filelist, (mpd_Song *) data, 0);
110                 break;
111         case PLAYLIST_EVENT_MOVE:
112                 break;
113         default:
114                 sync_highlights(c, browser->filelist);
115                 break;
116         }
119 /* list_window callback */
120 const char *
121 browser_lw_callback(unsigned idx, int *highlight, void *data)
123         static char buf[BUFSIZE];
124         mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
125         filelist_entry_t *entry;
126         mpd_InfoEntity *entity;
128         if( (entry=(filelist_entry_t *)g_list_nth_data(fl->list,idx))==NULL )
129                 return NULL;
131         entity = entry->entity;
132         *highlight = (entry->flags & HIGHLIGHT);
134         if( entity == NULL )
135                 return "[..]";
137         if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
138                 mpd_Directory *dir = entity->info.directory;
139                 char *directory = utf8_to_locale(basename(dir->path));
141                 g_snprintf(buf, BUFSIZE, "[%s]", directory);
142                 g_free(directory);
143                 return buf;
144         } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
145                 mpd_Song *song = entity->info.song;
147                 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
148                 return buf;
149         } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
150                 mpd_PlaylistFile *plf = entity->info.playlistFile;
151                 char *filename = utf8_to_locale(basename(plf->path));
153 #ifdef USE_OLD_LAYOUT
154                 g_snprintf(buf, BUFSIZE, "*%s*", filename);
155 #else
156                 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
157 #endif
158                 g_free(filename);
159                 return buf;
160         }
162         return "Error: Unknown entry!";
165 /* chdir */
166 int
167 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
168                          filelist_entry_t *entry, const char *new_path)
170         mpd_InfoEntity *entity = NULL;
171         gchar *path = NULL;
173         if( entry!=NULL )
174                 entity = entry->entity;
175         else if( new_path==NULL )
176                 return -1;
178         if( entity==NULL ) {
179                 if( entry || 0==strcmp(new_path, "..") ) {
180                         /* return to parent */
181                         char *parent = g_path_get_dirname(browser->filelist->path);
182                         if( strcmp(parent, ".") == 0 )
183                                 parent[0] = '\0';
184                         path = g_strdup(parent);
185                         list_window_reset(browser->lw);
186                         /* restore previous list window state */
187                         list_window_pop_state(browser->lw_state, browser->lw);
188                 } else {
189                         /* entry==NULL, then new_path ("" is root) */
190                         path = g_strdup(new_path);
191                         list_window_reset(browser->lw);
192                         /* restore first list window state (pop while returning true) */
193                         while(list_window_pop_state(browser->lw_state, browser->lw));
194                 }
195         } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
196                 /* enter sub */
197                 mpd_Directory *dir = entity->info.directory;
198                 path = utf8_to_locale(dir->path);
199                 /* save current list window state */
200                 list_window_push_state(browser->lw_state, browser->lw);
201         } else
202                 return -1;
204         mpdclient_filelist_free(browser->filelist);
205         browser->filelist = mpdclient_filelist_get(c, path);
206         sync_highlights(c, browser->filelist);
207         list_window_check_selected(browser->lw, browser->filelist->length);
208         g_free(path);
209         return 0;
212 static int
213 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
215         mpd_InfoEntity *entity = entry->entity;
216         mpd_PlaylistFile *plf = entity->info.playlistFile;
217         char *filename = utf8_to_locale(plf->path);
219         if (mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0)
220                 screen_status_printf(_("Loading playlist %s..."), basename(filename));
221         g_free(filename);
222         return 0;
225 static int
226 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
228         int idx;
229         mpd_InfoEntity *entity = entry->entity;
230         mpd_Song *song = entity->info.song;
232         if (!(entry->flags & HIGHLIGHT)) {
233                 if (mpdclient_cmd_add(c, song) == 0) {
234                         char buf[BUFSIZE];
236                         entry->flags |= HIGHLIGHT;
237                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
238                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
239                         mpdclient_update(c); /* get song id */
240                 } else
241                         return -1;
242         }
244         idx = playlist_get_index_from_file(c, song->file);
245         mpdclient_cmd_play(c, idx);
246         return 0;
249 int
250 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
252         filelist_entry_t *entry;
253         mpd_InfoEntity *entity;
255         if (browser->filelist == NULL)
256                 return -1;
257         entry = (filelist_entry_t *) g_list_nth_data(browser->filelist->list,
258                                                      browser->lw->selected);
259         if( entry==NULL )
260                 return -1;
262         entity = entry->entity;
263         if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
264                 return browser_change_directory(browser, c, entry, NULL);
265         else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
266                 return load_playlist(c, entry);
267         else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
268                 return enqueue_and_play(c, entry);
269         return -1;
273 #ifdef USE_OLD_ADD
274 /* NOTE - The add_directory functions should move to mpdclient.c */
275 extern gint mpdclient_finish_command(mpdclient_t *c);
277 static int
278 add_directory(mpdclient_t *c, char *dir)
280         mpd_InfoEntity *entity;
281         GList *subdir_list = NULL;
282         GList *list = NULL;
283         char *dirname;
285         dirname = utf8_to_locale(dir);
286         screen_status_printf(_("Adding directory %s...\n"), dirname);
287         doupdate();
288         g_free(dirname);
289         dirname = NULL;
291         mpd_sendLsInfoCommand(c->connection, dir);
292         mpd_sendCommandListBegin(c->connection);
293         while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
294                 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
295                         mpd_Song *song = entity->info.song;
296                         mpd_sendAddCommand(c->connection, song->file);
297                         mpd_freeInfoEntity(entity);
298                 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
299                         subdir_list = g_list_append(subdir_list, (gpointer) entity);
300                 } else
301                         mpd_freeInfoEntity(entity);
302         }
303         mpd_sendCommandListEnd(c->connection);
304         mpdclient_finish_command(c);
305         c->need_update = TRUE;
307         list = g_list_first(subdir_list);
308         while( list!=NULL ) {
309                 mpd_Directory *dir;
311                 entity = list->data;
312                 dir = entity->info.directory;
313                 add_directory(c, dir->path);
314                 mpd_freeInfoEntity(entity);
315                 list->data=NULL;
316                 list=list->next;
317         }
318         g_list_free(subdir_list);
319         return 0;
321 #endif
323 static int
324 browser_select_entry(mpdclient_t *c, filelist_entry_t *entry,
325                      gboolean toggle)
327         assert(entry != NULL);
328         assert(entry->entity != NULL);
330         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
331                 return load_playlist(c, entry);
333         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
334                 mpd_Directory *dir = entry->entity->info.directory;
335 #ifdef USE_OLD_ADD
336                 add_directory(c, tmp);
337 #else
338                 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
339                         char *tmp = utf8_to_locale(dir->path);
341                         screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
342                         g_free(tmp);
343                 }
344 #endif
345                 return 0;
346         }
348         if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
349                 return -1;
351         assert(entry->entity->info.song != NULL);
353         if (!toggle || (entry->flags & HIGHLIGHT) == 0) {
354                 mpd_Song *song = entry->entity->info.song;
356                 entry->flags |= HIGHLIGHT;
358                 if (mpdclient_cmd_add(c, song) == 0) {
359                         char buf[BUFSIZE];
361                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
362                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
363                 }
364         } else {
365                 /* remove song from playlist */
366                 mpd_Song *song = entry->entity->info.song;
367                 int idx;
369                 entry->flags &= ~HIGHLIGHT;
371                 while ((idx = playlist_get_index_from_file(c, song->file)) >=0)
372                         mpdclient_cmd_delete(c, idx);
373         }
375         return 0;
378 int
379 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
381         filelist_entry_t *entry;
383         if (browser->filelist == NULL)
384                 return -1;
385         entry = g_list_nth_data(browser->filelist->list, browser->lw->selected);
386         if (entry == NULL || entry->entity == NULL)
387                 return -1;
389         return browser_select_entry(c, entry, TRUE);
392 void
393 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
395         filelist_entry_t *entry;
396         GList *temp = browser->filelist->list;
398         if (browser->filelist == NULL)
399                 return;
401         for (browser->filelist->list = g_list_first(browser->filelist->list);
402              browser->filelist->list;
403              browser->filelist->list = g_list_next(browser->filelist->list)) {
404                 entry = browser->filelist->list->data;
405                 if (entry != NULL && entry->entity != NULL)
406                         browser_select_entry(c, entry, FALSE);
407         }
409         browser->filelist->list = temp;
412 #ifdef HAVE_GETMOUSE
413 int
414 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
416         int row;
417         unsigned prev_selected = browser->lw->selected;
418         unsigned long bstate;
419         int length;
421         if (browser->filelist)
422                 length = browser->filelist->length;
423         else
424                 length = 0;
426         if( screen_get_mouse_event(c, browser->lw, length, &bstate, &row) )
427                 return 1;
429         browser->lw->selected = browser->lw->start + row;
430         list_window_check_selected(browser->lw, length);
432         if( bstate & BUTTON1_CLICKED ) {
433                 if (prev_selected == browser->lw->selected)
434                         browser_handle_enter(browser, c);
435         } else if (bstate & BUTTON3_CLICKED) {
436                 if (prev_selected == browser->lw->selected)
437                         browser_handle_select(browser, c);
438         }
440         return 1;
442 #endif