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 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 void
55 set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight)
56 {
57 GList *list = g_list_first(fl->list);
59 if( !song )
60 return;
62 while( list ) {
63 filelist_entry_t *entry = list->data;
64 mpd_InfoEntity *entity = entry->entity;
66 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
67 mpd_Song *song2 = entity->info.song;
69 if( strcmp(song->file, song2->file) == 0 ) {
70 if(highlight)
71 entry->flags |= HIGHLIGHT;
72 else
73 entry->flags &= ~HIGHLIGHT;
74 }
75 }
76 list = list->next;
77 }
78 }
80 /* sync highlight flags with playlist */
81 void
82 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
83 {
84 GList *list = g_list_first(fl->list);
86 while(list) {
87 filelist_entry_t *entry = list->data;
88 mpd_InfoEntity *entity = entry->entity;
90 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
91 mpd_Song *song = entity->info.song;
93 if( playlist_get_index_from_file(c, song->file) >= 0 )
94 entry->flags |= HIGHLIGHT;
95 else
96 entry->flags &= ~HIGHLIGHT;
97 }
98 list=list->next;
99 }
100 }
102 /* list_window callback */
103 const char *
104 browser_lw_callback(unsigned idx, int *highlight, void *data)
105 {
106 static char buf[BUFSIZE];
107 mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
108 filelist_entry_t *entry;
109 mpd_InfoEntity *entity;
111 if( (entry=(filelist_entry_t *)g_list_nth_data(fl->list,idx))==NULL )
112 return NULL;
114 entity = entry->entity;
115 *highlight = (entry->flags & HIGHLIGHT);
117 if( entity == NULL )
118 return "[..]";
120 if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
121 mpd_Directory *dir = entity->info.directory;
122 char *directory = utf8_to_locale(basename(dir->path));
124 g_snprintf(buf, BUFSIZE, "[%s]", directory);
125 g_free(directory);
126 return buf;
127 } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
128 mpd_Song *song = entity->info.song;
130 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
131 return buf;
132 } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
133 mpd_PlaylistFile *plf = entity->info.playlistFile;
134 char *filename = utf8_to_locale(basename(plf->path));
136 #ifdef USE_OLD_LAYOUT
137 g_snprintf(buf, BUFSIZE, "*%s*", filename);
138 #else
139 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
140 #endif
141 g_free(filename);
142 return buf;
143 }
145 return "Error: Unknown entry!";
146 }
148 /* chdir */
149 int
150 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
151 filelist_entry_t *entry, const char *new_path)
152 {
153 mpd_InfoEntity *entity = NULL;
154 gchar *path = NULL;
156 if( entry!=NULL )
157 entity = entry->entity;
158 else if( new_path==NULL )
159 return -1;
161 if( entity==NULL ) {
162 if( entry || 0==strcmp(new_path, "..") ) {
163 /* return to parent */
164 char *parent = g_path_get_dirname(browser->filelist->path);
165 if( strcmp(parent, ".") == 0 )
166 parent[0] = '\0';
167 path = g_strdup(parent);
168 list_window_reset(browser->lw);
169 /* restore previous list window state */
170 list_window_pop_state(browser->lw_state, browser->lw);
171 } else {
172 /* entry==NULL, then new_path ("" is root) */
173 path = g_strdup(new_path);
174 list_window_reset(browser->lw);
175 /* restore first list window state (pop while returning true) */
176 while(list_window_pop_state(browser->lw_state, browser->lw));
177 }
178 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
179 /* enter sub */
180 mpd_Directory *dir = entity->info.directory;
181 path = utf8_to_locale(dir->path);
182 /* save current list window state */
183 list_window_push_state(browser->lw_state, browser->lw);
184 } else
185 return -1;
187 mpdclient_filelist_free(browser->filelist);
188 browser->filelist = mpdclient_filelist_get(c, path);
189 sync_highlights(c, browser->filelist);
190 list_window_check_selected(browser->lw, browser->filelist->length);
191 g_free(path);
192 return 0;
193 }
195 static int
196 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
197 {
198 mpd_InfoEntity *entity = entry->entity;
199 mpd_PlaylistFile *plf = entity->info.playlistFile;
200 char *filename = utf8_to_locale(plf->path);
202 if (mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0)
203 screen_status_printf(_("Loading playlist %s..."), basename(filename));
204 g_free(filename);
205 return 0;
206 }
208 static int
209 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
210 {
211 int idx;
212 mpd_InfoEntity *entity = entry->entity;
213 mpd_Song *song = entity->info.song;
215 if (!(entry->flags & HIGHLIGHT)) {
216 if (mpdclient_cmd_add(c, song) == 0) {
217 char buf[BUFSIZE];
219 entry->flags |= HIGHLIGHT;
220 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
221 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
222 mpdclient_update(c); /* get song id */
223 } else
224 return -1;
225 }
227 idx = playlist_get_index_from_file(c, song->file);
228 mpdclient_cmd_play(c, idx);
229 return 0;
230 }
232 int
233 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
234 {
235 filelist_entry_t *entry;
236 mpd_InfoEntity *entity;
238 if (browser->filelist == NULL)
239 return -1;
240 entry = (filelist_entry_t *) g_list_nth_data(browser->filelist->list,
241 browser->lw->selected);
242 if( entry==NULL )
243 return -1;
245 entity = entry->entity;
246 if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
247 return browser_change_directory(browser, c, entry, NULL);
248 else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
249 return load_playlist(c, entry);
250 else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
251 return enqueue_and_play(c, entry);
252 return -1;
253 }
256 #ifdef USE_OLD_ADD
257 /* NOTE - The add_directory functions should move to mpdclient.c */
258 extern gint mpdclient_finish_command(mpdclient_t *c);
260 static int
261 add_directory(mpdclient_t *c, char *dir)
262 {
263 mpd_InfoEntity *entity;
264 GList *subdir_list = NULL;
265 GList *list = NULL;
266 char *dirname;
268 dirname = utf8_to_locale(dir);
269 screen_status_printf(_("Adding directory %s...\n"), dirname);
270 doupdate();
271 g_free(dirname);
272 dirname = NULL;
274 mpd_sendLsInfoCommand(c->connection, dir);
275 mpd_sendCommandListBegin(c->connection);
276 while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
277 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
278 mpd_Song *song = entity->info.song;
279 mpd_sendAddCommand(c->connection, song->file);
280 mpd_freeInfoEntity(entity);
281 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
282 subdir_list = g_list_append(subdir_list, (gpointer) entity);
283 } else
284 mpd_freeInfoEntity(entity);
285 }
286 mpd_sendCommandListEnd(c->connection);
287 mpdclient_finish_command(c);
288 c->need_update = TRUE;
290 list = g_list_first(subdir_list);
291 while( list!=NULL ) {
292 mpd_Directory *dir;
294 entity = list->data;
295 dir = entity->info.directory;
296 add_directory(c, dir->path);
297 mpd_freeInfoEntity(entity);
298 list->data=NULL;
299 list=list->next;
300 }
301 g_list_free(subdir_list);
302 return 0;
303 }
304 #endif
306 int
307 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
308 {
309 filelist_entry_t *entry;
311 if (browser->filelist == NULL)
312 return -1;
313 entry = g_list_nth_data(browser->filelist->list, browser->lw->selected);
314 if (entry == NULL || entry->entity == NULL)
315 return -1;
317 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
318 return load_playlist(c, entry);
320 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
321 mpd_Directory *dir = entry->entity->info.directory;
322 #ifdef USE_OLD_ADD
323 add_directory(c, tmp);
324 #else
325 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
326 char *tmp = utf8_to_locale(dir->path);
328 screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
329 g_free(tmp);
330 }
331 #endif
332 return 0;
333 }
335 if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
336 return -1;
338 if (entry->flags & HIGHLIGHT)
339 entry->flags &= ~HIGHLIGHT;
340 else
341 entry->flags |= HIGHLIGHT;
343 if (entry->flags & HIGHLIGHT) {
344 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
345 mpd_Song *song = entry->entity->info.song;
347 if (mpdclient_cmd_add(c, song) == 0) {
348 char buf[BUFSIZE];
350 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
351 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
352 }
353 }
354 } else {
355 /* remove song from playlist */
356 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
357 mpd_Song *song = entry->entity->info.song;
359 if (song) {
360 int idx;
362 while ((idx = playlist_get_index_from_file(c, song->file)) >=0)
363 mpdclient_cmd_delete(c, idx);
364 }
365 }
366 }
368 return 0;
369 }
371 int
372 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
373 {
374 filelist_entry_t *entry;
375 GList *temp = browser->filelist->list;
377 if (browser->filelist == NULL)
378 return -1;
380 for (browser->filelist->list = g_list_first(browser->filelist->list);
381 browser->filelist->list;
382 browser->filelist->list = g_list_next(browser->filelist->list)) {
383 entry = browser->filelist->list->data;
384 if (entry == NULL || entry->entity == NULL)
385 return -1;
387 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
388 load_playlist(c, entry);
390 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
391 mpd_Directory *dir = entry->entity->info.directory;
392 #ifdef USE_OLD_ADD
393 add_directory(c, tmp);
394 #else
395 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
396 char *tmp = utf8_to_locale(dir->path);
398 screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
399 g_free(tmp);
400 }
401 #endif
402 }
404 if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
405 continue;
407 entry->flags |= HIGHLIGHT;
409 if (entry->flags & HIGHLIGHT) {
410 if (entry->entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
411 mpd_Song *song = entry->entity->info.song;
413 if (mpdclient_cmd_add(c, song) == 0) {
414 char buf[BUFSIZE];
416 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
417 screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
418 }
419 }
420 }
421 /*
422 else {
423 //remove song from playlist
424 if( entry->entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
425 mpd_Song *song = entry->entity->info.song;
427 if( song ) {
428 int idx = playlist_get_index_from_file(c, song->file);
430 while( (idx=playlist_get_index_from_file(c, song->file))>=0 )
431 mpdclient_cmd_delete(c, idx);
432 }
433 }
434 }
435 */
436 return 0;
437 }
439 browser->filelist->list = temp;
440 return 0;
441 }
443 #ifdef HAVE_GETMOUSE
444 int
445 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
446 {
447 int row;
448 unsigned prev_selected = browser->lw->selected;
449 unsigned long bstate;
450 int length;
452 if (browser->filelist)
453 length = browser->filelist->length;
454 else
455 length = 0;
457 if( screen_get_mouse_event(c, browser->lw, length, &bstate, &row) )
458 return 1;
460 browser->lw->selected = browser->lw->start + row;
461 list_window_check_selected(browser->lw, length);
463 if( bstate & BUTTON1_CLICKED ) {
464 if (prev_selected == browser->lw->selected)
465 browser_handle_enter(browser, c);
466 } else if (bstate & BUTTON3_CLICKED) {
467 if (prev_selected == browser->lw->selected)
468 browser_handle_select(browser, c);
469 }
471 return 1;
472 }
473 #endif