828cbe21ca6c2749ffda7b909aeda3002e38d6ca
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 }
117 }
119 /* list_window callback */
120 const char *
121 browser_lw_callback(unsigned idx, int *highlight, void *data)
122 {
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!";
163 }
165 /* chdir */
166 int
167 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
168 filelist_entry_t *entry, const char *new_path)
169 {
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;
210 }
212 static int
213 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
214 {
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;
223 }
225 static int
226 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
227 {
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;
247 }
249 int
250 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
251 {
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;
270 }
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)
279 {
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;
320 }
321 #endif
323 static int
324 browser_select_entry(mpdclient_t *c, filelist_entry_t *entry,
325 gboolean toggle)
326 {
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;
376 }
378 int
379 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
380 {
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);
390 }
392 void
393 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
394 {
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;
410 }
412 #ifdef HAVE_GETMOUSE
413 int
414 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
415 {
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;
441 }
442 #endif