dbc7adad3c97054e19cf88a13a3de1b9ee39ef1c
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 GList *list = g_list_first(fl->list);
59 assert(song != NULL);
61 while( list ) {
62 filelist_entry_t *entry = list->data;
63 mpd_InfoEntity *entity = entry->entity;
65 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
66 mpd_Song *song2 = entity->info.song;
68 if( strcmp(song->file, song2->file) == 0 ) {
69 if(highlight)
70 entry->flags |= HIGHLIGHT;
71 else
72 entry->flags &= ~HIGHLIGHT;
73 }
74 }
75 list = list->next;
76 }
77 }
79 /* sync highlight flags with playlist */
80 void
81 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
82 {
83 GList *list = g_list_first(fl->list);
85 while(list) {
86 filelist_entry_t *entry = list->data;
87 mpd_InfoEntity *entity = entry->entity;
89 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
90 mpd_Song *song = entity->info.song;
92 if( playlist_get_index_from_file(c, song->file) >= 0 )
93 entry->flags |= HIGHLIGHT;
94 else
95 entry->flags &= ~HIGHLIGHT;
96 }
97 list=list->next;
98 }
99 }
101 /* the playlist have been updated -> fix highlights */
102 void
103 browser_playlist_changed(struct screen_browser *browser, mpdclient_t *c,
104 int event, gpointer data)
105 {
106 if (browser->filelist == NULL)
107 return;
109 D("screen_file.c> playlist_callback() [%d]\n", event);
110 switch(event) {
111 case PLAYLIST_EVENT_CLEAR:
112 clear_highlights(browser->filelist);
113 break;
114 case PLAYLIST_EVENT_ADD:
115 set_highlight(browser->filelist, (mpd_Song *) data, 1);
116 break;
117 case PLAYLIST_EVENT_DELETE:
118 set_highlight(browser->filelist, (mpd_Song *) data, 0);
119 break;
120 case PLAYLIST_EVENT_MOVE:
121 break;
122 default:
123 sync_highlights(c, browser->filelist);
124 break;
125 }
126 }
128 /* list_window callback */
129 const char *
130 browser_lw_callback(unsigned idx, int *highlight, void *data)
131 {
132 static char buf[BUFSIZE];
133 mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
134 filelist_entry_t *entry;
135 mpd_InfoEntity *entity;
137 if( (entry=(filelist_entry_t *)g_list_nth_data(fl->list,idx))==NULL )
138 return NULL;
140 entity = entry->entity;
141 *highlight = (entry->flags & HIGHLIGHT);
143 if( entity == NULL )
144 return "[..]";
146 if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
147 mpd_Directory *dir = entity->info.directory;
148 char *directory = utf8_to_locale(basename(dir->path));
150 g_snprintf(buf, BUFSIZE, "[%s]", directory);
151 g_free(directory);
152 return buf;
153 } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
154 mpd_Song *song = entity->info.song;
156 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
157 return buf;
158 } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
159 mpd_PlaylistFile *plf = entity->info.playlistFile;
160 char *filename = utf8_to_locale(basename(plf->path));
162 #ifdef USE_OLD_LAYOUT
163 g_snprintf(buf, BUFSIZE, "*%s*", filename);
164 #else
165 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
166 #endif
167 g_free(filename);
168 return buf;
169 }
171 return "Error: Unknown entry!";
172 }
174 /* chdir */
175 int
176 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
177 filelist_entry_t *entry, const char *new_path)
178 {
179 mpd_InfoEntity *entity = NULL;
180 gchar *path = NULL;
182 if( entry!=NULL )
183 entity = entry->entity;
184 else if( new_path==NULL )
185 return -1;
187 if( entity==NULL ) {
188 if( entry || 0==strcmp(new_path, "..") ) {
189 /* return to parent */
190 char *parent = g_path_get_dirname(browser->filelist->path);
191 if( strcmp(parent, ".") == 0 )
192 parent[0] = '\0';
193 path = g_strdup(parent);
194 list_window_reset(browser->lw);
195 /* restore previous list window state */
196 list_window_pop_state(browser->lw_state, browser->lw);
197 } else {
198 /* entry==NULL, then new_path ("" is root) */
199 path = g_strdup(new_path);
200 list_window_reset(browser->lw);
201 /* restore first list window state (pop while returning true) */
202 while(list_window_pop_state(browser->lw_state, browser->lw));
203 }
204 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
205 /* enter sub */
206 mpd_Directory *dir = entity->info.directory;
207 path = utf8_to_locale(dir->path);
208 /* save current list window state */
209 list_window_push_state(browser->lw_state, browser->lw);
210 } else
211 return -1;
213 mpdclient_filelist_free(browser->filelist);
214 browser->filelist = mpdclient_filelist_get(c, path);
215 sync_highlights(c, browser->filelist);
216 list_window_check_selected(browser->lw, browser->filelist->length);
217 g_free(path);
218 return 0;
219 }
221 static int
222 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
223 {
224 mpd_InfoEntity *entity = entry->entity;
225 mpd_PlaylistFile *plf = entity->info.playlistFile;
226 char *filename = utf8_to_locale(plf->path);
228 if (mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0)
229 screen_status_printf(_("Loading playlist %s..."), basename(filename));
230 g_free(filename);
231 return 0;
232 }
234 static int
235 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
236 {
237 int idx;
238 mpd_InfoEntity *entity = entry->entity;
239 mpd_Song *song = entity->info.song;
241 if (!(entry->flags & HIGHLIGHT)) {
242 if (mpdclient_cmd_add(c, song) == 0) {
243 char buf[BUFSIZE];
245 entry->flags |= HIGHLIGHT;
246 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
247 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
248 mpdclient_update(c); /* get song id */
249 } else
250 return -1;
251 }
253 idx = playlist_get_index_from_file(c, song->file);
254 mpdclient_cmd_play(c, idx);
255 return 0;
256 }
258 int
259 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
260 {
261 filelist_entry_t *entry;
262 mpd_InfoEntity *entity;
264 if (browser->filelist == NULL)
265 return -1;
266 entry = (filelist_entry_t *) g_list_nth_data(browser->filelist->list,
267 browser->lw->selected);
268 if( entry==NULL )
269 return -1;
271 entity = entry->entity;
272 if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
273 return browser_change_directory(browser, c, entry, NULL);
274 else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
275 return load_playlist(c, entry);
276 else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
277 return enqueue_and_play(c, entry);
278 return -1;
279 }
282 #ifdef USE_OLD_ADD
283 /* NOTE - The add_directory functions should move to mpdclient.c */
284 extern gint mpdclient_finish_command(mpdclient_t *c);
286 static int
287 add_directory(mpdclient_t *c, char *dir)
288 {
289 mpd_InfoEntity *entity;
290 GList *subdir_list = NULL;
291 GList *list = NULL;
292 char *dirname;
294 dirname = utf8_to_locale(dir);
295 screen_status_printf(_("Adding directory %s...\n"), dirname);
296 doupdate();
297 g_free(dirname);
298 dirname = NULL;
300 mpd_sendLsInfoCommand(c->connection, dir);
301 mpd_sendCommandListBegin(c->connection);
302 while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
303 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
304 mpd_Song *song = entity->info.song;
305 mpd_sendAddCommand(c->connection, song->file);
306 mpd_freeInfoEntity(entity);
307 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
308 subdir_list = g_list_append(subdir_list, (gpointer) entity);
309 } else
310 mpd_freeInfoEntity(entity);
311 }
312 mpd_sendCommandListEnd(c->connection);
313 mpdclient_finish_command(c);
314 c->need_update = TRUE;
316 list = g_list_first(subdir_list);
317 while( list!=NULL ) {
318 mpd_Directory *dir;
320 entity = list->data;
321 dir = entity->info.directory;
322 add_directory(c, dir->path);
323 mpd_freeInfoEntity(entity);
324 list->data=NULL;
325 list=list->next;
326 }
327 g_list_free(subdir_list);
328 return 0;
329 }
330 #endif
332 static int
333 browser_select_entry(mpdclient_t *c, filelist_entry_t *entry,
334 gboolean toggle)
335 {
336 assert(entry != NULL);
337 assert(entry->entity != NULL);
339 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
340 return load_playlist(c, entry);
342 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
343 mpd_Directory *dir = entry->entity->info.directory;
344 #ifdef USE_OLD_ADD
345 add_directory(c, tmp);
346 #else
347 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
348 char *tmp = utf8_to_locale(dir->path);
350 screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
351 g_free(tmp);
352 }
353 #endif
354 return 0;
355 }
357 if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
358 return -1;
360 assert(entry->entity->info.song != NULL);
362 if (!toggle || (entry->flags & HIGHLIGHT) == 0) {
363 mpd_Song *song = entry->entity->info.song;
365 entry->flags |= HIGHLIGHT;
367 if (mpdclient_cmd_add(c, song) == 0) {
368 char buf[BUFSIZE];
370 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
371 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
372 }
373 } else {
374 /* remove song from playlist */
375 mpd_Song *song = entry->entity->info.song;
376 int idx;
378 entry->flags &= ~HIGHLIGHT;
380 while ((idx = playlist_get_index_from_file(c, song->file)) >=0)
381 mpdclient_cmd_delete(c, idx);
382 }
384 return 0;
385 }
387 int
388 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
389 {
390 filelist_entry_t *entry;
392 if (browser->filelist == NULL)
393 return -1;
394 entry = g_list_nth_data(browser->filelist->list, browser->lw->selected);
395 if (entry == NULL || entry->entity == NULL)
396 return -1;
398 return browser_select_entry(c, entry, TRUE);
399 }
401 void
402 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
403 {
404 filelist_entry_t *entry;
405 GList *temp = browser->filelist->list;
407 if (browser->filelist == NULL)
408 return;
410 for (browser->filelist->list = g_list_first(browser->filelist->list);
411 browser->filelist->list;
412 browser->filelist->list = g_list_next(browser->filelist->list)) {
413 entry = browser->filelist->list->data;
414 if (entry != NULL && entry->entity != NULL)
415 browser_select_entry(c, entry, FALSE);
416 }
418 browser->filelist->list = temp;
419 }
421 #ifdef HAVE_GETMOUSE
422 int
423 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
424 {
425 int row;
426 unsigned prev_selected = browser->lw->selected;
427 unsigned long bstate;
428 int length;
430 if (browser->filelist)
431 length = browser->filelist->length;
432 else
433 length = 0;
435 if( screen_get_mouse_event(c, browser->lw, length, &bstate, &row) )
436 return 1;
438 browser->lw->selected = browser->lw->start + row;
439 list_window_check_selected(browser->lw, length);
441 if( bstate & BUTTON1_CLICKED ) {
442 if (prev_selected == browser->lw->selected)
443 browser_handle_enter(browser, c);
444 } else if (bstate & BUTTON3_CLICKED) {
445 if (prev_selected == browser->lw->selected)
446 browser_handle_select(browser, c);
447 }
449 return 1;
450 }
451 #endif