Code

removed LIST_FORMAT, STATUS_FORMAT
[ncmpc.git] / src / screen_browser.c
1 /*
2  * (c) 2004 by Kalle Wallin <kaw@linux.se>
3  * Copyright (C) 2008 Max Kellermann <max@duempel.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
20 #include "screen_browser.h"
21 #include "i18n.h"
22 #include "options.h"
23 #include "support.h"
24 #include "strfsong.h"
25 #include "screen_utils.h"
26 #include "gcc.h"
28 #include <string.h>
30 #define USE_OLD_LAYOUT
31 #undef  USE_OLD_ADD
33 #define BUFSIZE 1024
35 #define HIGHLIGHT  (0x01)
37 /* clear the highlight flag for all items in the filelist */
38 static void
39 clear_highlights(mpdclient_filelist_t *fl)
40 {
41         guint i;
43         for (i = 0; i < filelist_length(fl); ++i) {
44                 struct filelist_entry *entry = filelist_get(fl, i);
46                 entry->flags &= ~HIGHLIGHT;
47         }
48 }
50 /* change the highlight flag for a song */
51 static void
52 set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight)
53 {
54         struct filelist_entry *entry = filelist_find_song(fl, song);
55         mpd_InfoEntity *entity;
57         if (entry == NULL)
58                 return;
60         entity = entry->entity;
61         if (highlight)
62                 entry->flags |= HIGHLIGHT;
63         else
64                 entry->flags &= ~HIGHLIGHT;
65 }
67 /* sync highlight flags with playlist */
68 void
69 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
70 {
71         guint i;
73         for (i = 0; i < filelist_length(fl); ++i) {
74                 struct filelist_entry *entry = filelist_get(fl, i);
75                 mpd_InfoEntity *entity = entry->entity;
77                 if ( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
78                         mpd_Song *song = entity->info.song;
80                         if( playlist_get_index_from_file(c, song->file) >= 0 )
81                                 entry->flags |= HIGHLIGHT;
82                         else
83                                 entry->flags &= ~HIGHLIGHT;
84                 }
85         }
86 }
88 /* the playlist have been updated -> fix highlights */
89 void
90 browser_playlist_changed(struct screen_browser *browser, mpdclient_t *c,
91                          int event, gpointer data)
92 {
93         if (browser->filelist == NULL)
94                 return;
96         switch(event) {
97         case PLAYLIST_EVENT_CLEAR:
98                 clear_highlights(browser->filelist);
99                 break;
100         case PLAYLIST_EVENT_ADD:
101                 set_highlight(browser->filelist, (mpd_Song *) data, 1);
102                 break;
103         case PLAYLIST_EVENT_DELETE:
104                 set_highlight(browser->filelist, (mpd_Song *) data, 0);
105                 break;
106         case PLAYLIST_EVENT_MOVE:
107                 break;
108         default:
109                 sync_highlights(c, browser->filelist);
110                 break;
111         }
114 /* list_window callback */
115 const char *
116 browser_lw_callback(unsigned idx, int *highlight, void *data)
118         static char buf[BUFSIZE];
119         mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
120         filelist_entry_t *entry;
121         mpd_InfoEntity *entity;
123         if (idx >= filelist_length(fl))
124                 return NULL;
126         entry = filelist_get(fl, idx);
127         assert(entry != NULL);
129         entity = entry->entity;
130         *highlight = (entry->flags & HIGHLIGHT);
132         if( entity == NULL )
133                 return "[..]";
135         if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
136                 mpd_Directory *dir = entity->info.directory;
137                 char *directory = utf8_to_locale(basename(dir->path));
139                 g_snprintf(buf, BUFSIZE, "[%s]", directory);
140                 g_free(directory);
141                 return buf;
142         } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
143                 mpd_Song *song = entity->info.song;
145                 strfsong(buf, BUFSIZE, options.list_format, song);
146                 return buf;
147         } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
148                 mpd_PlaylistFile *plf = entity->info.playlistFile;
149                 char *filename = utf8_to_locale(basename(plf->path));
151 #ifdef USE_OLD_LAYOUT
152                 g_snprintf(buf, BUFSIZE, "*%s*", filename);
153 #else
154                 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
155 #endif
156                 g_free(filename);
157                 return buf;
158         }
160         return "Error: Unknown entry!";
163 /* chdir */
164 int
165 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
166                          filelist_entry_t *entry, const char *new_path)
168         mpd_InfoEntity *entity = NULL;
169         gchar *path = NULL;
171         if( entry!=NULL )
172                 entity = entry->entity;
173         else if( new_path==NULL )
174                 return -1;
176         if( entity==NULL ) {
177                 if( entry || 0==strcmp(new_path, "..") ) {
178                         /* return to parent */
179                         char *parent = g_path_get_dirname(browser->filelist->path);
180                         if( strcmp(parent, ".") == 0 )
181                                 parent[0] = '\0';
182                         path = g_strdup(parent);
183                         list_window_reset(browser->lw);
184                         /* restore previous list window state */
185                         list_window_pop_state(browser->lw_state, browser->lw);
186                 } else {
187                         /* entry==NULL, then new_path ("" is root) */
188                         path = g_strdup(new_path);
189                         list_window_reset(browser->lw);
190                         /* restore first list window state (pop while returning true) */
191                         while(list_window_pop_state(browser->lw_state, browser->lw));
192                 }
193         } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
194                 /* enter sub */
195                 mpd_Directory *dir = entity->info.directory;
196                 path = utf8_to_locale(dir->path);
197                 /* save current list window state */
198                 list_window_push_state(browser->lw_state, browser->lw);
199         } else
200                 return -1;
202         filelist_free(browser->filelist);
203         browser->filelist = mpdclient_filelist_get(c, path);
204         sync_highlights(c, browser->filelist);
205         list_window_check_selected(browser->lw, filelist_length(browser->filelist));
206         g_free(path);
207         return 0;
210 static int
211 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
213         mpd_InfoEntity *entity = entry->entity;
214         mpd_PlaylistFile *plf = entity->info.playlistFile;
215         char *filename = utf8_to_locale(plf->path);
217         if (mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0)
218                 screen_status_printf(_("Loading playlist %s..."), basename(filename));
219         g_free(filename);
220         return 0;
223 static int
224 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
226         int idx;
227         mpd_InfoEntity *entity = entry->entity;
228         mpd_Song *song = entity->info.song;
230         if (!(entry->flags & HIGHLIGHT)) {
231                 if (mpdclient_cmd_add(c, song) == 0) {
232                         char buf[BUFSIZE];
234                         entry->flags |= HIGHLIGHT;
235                         strfsong(buf, BUFSIZE, options.list_format, song);
236                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
237                         mpdclient_update(c); /* get song id */
238                 } else
239                         return -1;
240         }
242         idx = playlist_get_index_from_file(c, song->file);
243         mpdclient_cmd_play(c, idx);
244         return 0;
247 static struct filelist_entry *
248 browser_get_selected(const struct screen_browser *browser)
250         if (browser->filelist == NULL ||
251             browser->lw->selected >= filelist_length(browser->filelist))
252                 return NULL;
254         return filelist_get(browser->filelist, browser->lw->selected);
257 static int
258 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
260         struct filelist_entry *entry = browser_get_selected(browser);
261         mpd_InfoEntity *entity;
263         if( entry==NULL )
264                 return -1;
266         entity = entry->entity;
267         if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
268                 return browser_change_directory(browser, c, entry, NULL);
269         else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
270                 return load_playlist(c, entry);
271         else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
272                 return enqueue_and_play(c, entry);
273         return -1;
277 #ifdef USE_OLD_ADD
278 /* NOTE - The add_directory functions should move to mpdclient.c */
279 extern gint mpdclient_finish_command(mpdclient_t *c);
281 static int
282 add_directory(mpdclient_t *c, char *dir)
284         mpd_InfoEntity *entity;
285         GList *subdir_list = NULL;
286         GList *list = NULL;
287         char *dirname;
289         dirname = utf8_to_locale(dir);
290         screen_status_printf(_("Adding directory %s...\n"), dirname);
291         doupdate();
292         g_free(dirname);
293         dirname = NULL;
295         mpd_sendLsInfoCommand(c->connection, dir);
296         mpd_sendCommandListBegin(c->connection);
297         while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
298                 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
299                         mpd_Song *song = entity->info.song;
300                         mpd_sendAddCommand(c->connection, song->file);
301                         mpd_freeInfoEntity(entity);
302                 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
303                         subdir_list = g_list_append(subdir_list, (gpointer) entity);
304                 } else
305                         mpd_freeInfoEntity(entity);
306         }
307         mpd_sendCommandListEnd(c->connection);
308         mpdclient_finish_command(c);
309         c->need_update = TRUE;
311         list = g_list_first(subdir_list);
312         while( list!=NULL ) {
313                 mpd_Directory *dir;
315                 entity = list->data;
316                 dir = entity->info.directory;
317                 add_directory(c, dir->path);
318                 mpd_freeInfoEntity(entity);
319                 list->data=NULL;
320                 list=list->next;
321         }
322         g_list_free(subdir_list);
323         return 0;
325 #endif
327 static int
328 browser_select_entry(mpdclient_t *c, filelist_entry_t *entry,
329                      gboolean toggle)
331         assert(entry != NULL);
332         assert(entry->entity != NULL);
334         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
335                 return load_playlist(c, entry);
337         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
338                 mpd_Directory *dir = entry->entity->info.directory;
339 #ifdef USE_OLD_ADD
340                 add_directory(c, tmp);
341 #else
342                 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
343                         char *tmp = utf8_to_locale(dir->path);
345                         screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
346                         g_free(tmp);
347                 }
348 #endif
349                 return 0;
350         }
352         if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
353                 return -1;
355         assert(entry->entity->info.song != NULL);
357         if (!toggle || (entry->flags & HIGHLIGHT) == 0) {
358                 mpd_Song *song = entry->entity->info.song;
360                 entry->flags |= HIGHLIGHT;
362                 if (mpdclient_cmd_add(c, song) == 0) {
363                         char buf[BUFSIZE];
365                         strfsong(buf, BUFSIZE, options.list_format, song);
366                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
367                 }
368         } else {
369                 /* remove song from playlist */
370                 mpd_Song *song = entry->entity->info.song;
371                 int idx;
373                 entry->flags &= ~HIGHLIGHT;
375                 while ((idx = playlist_get_index_from_file(c, song->file)) >=0)
376                         mpdclient_cmd_delete(c, idx);
377         }
379         return 0;
382 static int
383 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
385         struct filelist_entry *entry = browser_get_selected(browser);
387         if (entry == NULL || entry->entity == NULL)
388                 return -1;
390         return browser_select_entry(c, entry, TRUE);
393 static int
394 browser_handle_add(struct screen_browser *browser, mpdclient_t *c)
396         struct filelist_entry *entry = browser_get_selected(browser);
398         if (entry == NULL || entry->entity == NULL)
399                 return -1;
401         return browser_select_entry(c, entry, FALSE);
404 static void
405 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
407         guint i;
409         if (browser->filelist == NULL)
410                 return;
412         for (i = 0; i < filelist_length(browser->filelist); ++i) {
413                 struct filelist_entry *entry = filelist_get(browser->filelist, i);
415                 if (entry != NULL && entry->entity != NULL)
416                         browser_select_entry(c, entry, FALSE);
417         }
420 #ifdef HAVE_GETMOUSE
421 static int
422 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
424         int row;
425         unsigned prev_selected = browser->lw->selected;
426         unsigned long bstate;
427         int length;
429         if (browser->filelist)
430                 length = filelist_length(browser->filelist);
431         else
432                 length = 0;
434         if (screen_get_mouse_event(c, &bstate, &row) ||
435             list_window_mouse(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;
451 #endif
453 bool
454 browser_cmd(struct screen_browser *browser, struct screen *screen,
455             struct mpdclient *c, command_t cmd)
457         struct filelist_entry *entry;
459         switch (cmd) {
460         case CMD_PLAY:
461                 browser_handle_enter(browser, c);
462                 return true;
464         case CMD_SELECT:
465                 if (browser_handle_select(browser, c) == 0)
466                         /* continue and select next item... */
467                         cmd = CMD_LIST_NEXT;
469                 /* call list_window_cmd to go to the next item */
470                 break;
472         case CMD_ADD:
473                 if (browser_handle_add(browser, c) == 0)
474                         /* continue and select next item... */
475                         cmd = CMD_LIST_NEXT;
477                 /* call list_window_cmd to go to the next item */
478                 break;
480         case CMD_SELECT_ALL:
481                 browser_handle_select_all(browser, c);
482                 return true;
484         case CMD_LIST_FIND:
485         case CMD_LIST_RFIND:
486         case CMD_LIST_FIND_NEXT:
487         case CMD_LIST_RFIND_NEXT:
488                 screen_find(screen,
489                             browser->lw, filelist_length(browser->filelist),
490                             cmd, browser_lw_callback,
491                             browser->filelist);
492                 return true;
494 #ifdef HAVE_GETMOUSE
495         case CMD_MOUSE_EVENT:
496                 browser_handle_mouse_event(browser, c);
497                 return true;
498 #endif
500 #ifdef ENABLE_LYRICS_SCREEN
501         case CMD_SCREEN_LYRICS:
502                 entry = browser_get_selected(browser);
503                 if (entry == NULL)
504                         return false;
506                 if (entry->entity == NULL ||
507                     entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
508                         return true;
510                 screen_lyrics_switch(c, entry->entity->info.song);
511                 return true;
512 #endif
514         default:
515                 break;
516         }
518         if (list_window_cmd(browser->lw, filelist_length(browser->filelist),
519                             cmd))
520                 return true;
522         return false;