Code

filelist: removed "path" attribute
[ncmpc.git] / src / screen_file.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2009 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
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.
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.
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 #include "config.h"
20 #include "i18n.h"
21 #include "options.h"
22 #include "charset.h"
23 #include "mpdclient.h"
24 #include "command.h"
25 #include "screen.h"
26 #include "screen_utils.h"
27 #include "screen_browser.h"
28 #include "screen_play.h"
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <glib.h>
35 static struct screen_browser browser;
36 static char *current_path;
38 static void
39 browse_paint(void);
41 static void
42 file_repaint(void)
43 {
44         browse_paint();
45         wrefresh(browser.lw->w);
46 }
48 static void
49 file_repaint_if_active(void)
50 {
51         if (screen_is_visible(&screen_browse))
52                 file_repaint();
53 }
55 static void
56 file_reload(struct mpdclient *c)
57 {
58         if (browser.filelist != NULL)
59                 filelist_free(browser.filelist);
61         browser.filelist = mpdclient_filelist_get(c, current_path);
62 }
64 /* the db has changed -> update the filelist */
65 static void
66 file_changed_callback(mpdclient_t *c, G_GNUC_UNUSED int event,
67                       G_GNUC_UNUSED gpointer data)
68 {
69         file_reload(c);
71 #ifndef NCMPC_MINI
72         sync_highlights(c, browser.filelist);
73 #endif
74         list_window_check_selected(browser.lw, filelist_length(browser.filelist));
76         file_repaint_if_active();
77 }
79 #ifndef NCMPC_MINI
80 /* the playlist has been updated -> fix highlights */
81 static void
82 playlist_changed_callback(mpdclient_t *c, int event, gpointer data)
83 {
84         browser_playlist_changed(&browser, c, event, data);
86         file_repaint_if_active();
87 }
88 #endif
90 static bool
91 file_change_directory(mpdclient_t *c, filelist_entry_t *entry,
92                       const char *new_path)
93 {
94         mpd_InfoEntity *entity = NULL;
95         gchar *path = NULL;
96         char *old_path;
97         int idx;
99         if( entry!=NULL )
100                 entity = entry->entity;
101         else if( new_path==NULL )
102                 return false;
104         if( entity==NULL ) {
105                 if( entry || 0==strcmp(new_path, "..") ) {
106                         /* return to parent */
107                         char *parent = g_path_get_dirname(current_path);
108                         if( strcmp(parent, ".") == 0 )
109                                 parent[0] = '\0';
110                         path = g_strdup(parent);
111                         g_free(parent);
112                 } else {
113                         /* entry==NULL, then new_path ("" is root) */
114                         path = g_strdup(new_path);
115                 }
116         } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
117                 /* enter sub */
118                 mpd_Directory *dir = entity->info.directory;
119                 path = g_strdup(dir->path);
120         } else
121                 return false;
123         old_path = current_path;
124         current_path = g_strdup(path);
126         file_reload(c);
128 #ifndef NCMPC_MINI
129         sync_highlights(c, browser.filelist);
130 #endif
132         idx = old_path != NULL
133                 ? filelist_find_directory(browser.filelist, old_path)
134                 : -1;
135         g_free(old_path);
137         list_window_reset(browser.lw);
138         if (idx >= 0) {
139                 list_window_set_selected(browser.lw, idx);
140                 list_window_center(browser.lw,
141                                    filelist_length(browser.filelist), idx);
142         }
144         g_free(path);
145         return true;
148 static bool
149 file_handle_enter(struct mpdclient *c)
151         struct filelist_entry *entry = browser_get_selected_entry(&browser);
152         struct mpd_InfoEntity *entity;
154         if (entry == NULL)
155                 return false;
157         entity = entry->entity;
158         if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
159                 return file_change_directory(c, entry, NULL);
160         else
161                 return false;
164 static int
165 handle_save(mpdclient_t *c)
167         filelist_entry_t *entry;
168         char *defaultname = NULL;
169         int ret;
170         unsigned selected;
172         if (browser.lw->selected >= filelist_length(browser.filelist))
173                 return -1;
175         for(selected = browser.lw->selected_start; selected <= browser.lw->selected_end; ++selected)
176         {
177                 entry = filelist_get(browser.filelist, selected);
178                 if( entry && entry->entity ) {
179                         mpd_InfoEntity *entity = entry->entity;
180                         if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
181                                 mpd_PlaylistFile *plf = entity->info.playlistFile;
182                                 defaultname = plf->path;
183                         }
184                 }
185         }
187         if(defaultname)
188                 defaultname = utf8_to_locale(defaultname);
189         ret = playlist_save(c, NULL, defaultname);
190         g_free(defaultname);
192         return ret;
195 static int
196 handle_delete(mpdclient_t *c)
198         filelist_entry_t *entry;
199         mpd_InfoEntity *entity;
200         mpd_PlaylistFile *plf;
201         char *str, *buf;
202         int key;
203         unsigned selected;
205         for(selected = browser.lw->selected_start; selected <= browser.lw->selected_end; ++selected)
206         {
207                 if (selected >= filelist_length(browser.filelist))
208                         return -1;
210                 entry = filelist_get(browser.filelist, selected);
211                 if( entry==NULL || entry->entity==NULL )
212                         continue;
214                 entity = entry->entity;
216                 if( entity->type!=MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
217                         /* translators: the "delete" command is only possible
218                            for playlists; the user attempted to delete a song
219                            or a directory or something else */
220                         screen_status_printf(_("Deleting this item is not possible"));
221                         screen_bell();
222                         continue;
223                 }
225                 plf = entity->info.playlistFile;
226                 str = utf8_to_locale(g_basename(plf->path));
227                 buf = g_strdup_printf(_("Delete playlist %s [%s/%s] ? "), str, YES, NO);
228                 g_free(str);
229                 key = tolower(screen_getch(screen.status_window.w, buf));
230                 g_free(buf);
231                 if( key != YES[0] ) {
232                         /* translators: a dialog was aborted by the user */
233                         screen_status_printf(_("Aborted"));
234                         return 0;
235                 }
237                 if( mpdclient_cmd_delete_playlist(c, plf->path) )
238                         continue;
240                 /* translators: MPD deleted the playlist, as requested by the
241                    user */
242                 screen_status_printf(_("Playlist deleted"));
243         }
244         return 0;
247 static void
248 browse_init(WINDOW *w, int cols, int rows)
250         current_path = g_strdup("");
252         browser.lw = list_window_init(w, cols, rows);
255 static void
256 browse_resize(int cols, int rows)
258         browser.lw->cols = cols;
259         browser.lw->rows = rows;
262 static void
263 browse_exit(void)
265         if (browser.filelist)
266                 filelist_free(browser.filelist);
267         list_window_free(browser.lw);
269         g_free(current_path);
272 static void
273 browse_open(G_GNUC_UNUSED mpdclient_t *c)
275         if (browser.filelist == NULL) {
276                 browser.filelist = mpdclient_filelist_get(c, "");
277 #ifndef NCMPC_MINI
278                 mpdclient_install_playlist_callback(c, playlist_changed_callback);
279 #endif
280                 mpdclient_install_browse_callback(c, file_changed_callback);
281         }
284 static const char *
285 browse_title(char *str, size_t size)
287         const char *path = NULL, *prev = NULL, *slash = current_path;
288         char *path_locale;
290         /* determine the last 2 parts of the path */
291         while ((slash = strchr(slash, '/')) != NULL) {
292                 path = prev;
293                 prev = ++slash;
294         }
296         if (path == NULL)
297                 /* fall back to full path */
298                 path = current_path;
300         path_locale = utf8_to_locale(path);
301         g_snprintf(str, size, "%s: %s",
302                    /* translators: caption of the browser screen */
303                    _("Browse"), path_locale);
304         g_free(path_locale);
305         return str;
308 static void
309 browse_paint(void)
311         list_window_paint(browser.lw, browser_lw_callback, browser.filelist);
314 static bool
315 browse_cmd(mpdclient_t *c, command_t cmd)
317         switch(cmd) {
318         case CMD_PLAY:
319                 if (file_handle_enter(c)) {
320                         file_repaint();
321                         return true;
322                 }
324                 break;
326         case CMD_GO_ROOT_DIRECTORY:
327                 file_change_directory(c, NULL, "");
328                 file_repaint();
329                 return true;
330         case CMD_GO_PARENT_DIRECTORY:
331                 file_change_directory(c, NULL, "..");
332                 file_repaint();
333                 return true;
335         case CMD_LOCATE:
336                 /* don't let browser_cmd() evaluate the locate command
337                    - it's a no-op, and by the way, leads to a
338                    segmentation fault in the current implementation */
339                 return false;
341         case CMD_DELETE:
342                 handle_delete(c);
343                 file_repaint();
344                 break;
345         case CMD_SAVE_PLAYLIST:
346                 handle_save(c);
347                 break;
348         case CMD_SCREEN_UPDATE:
349                 file_reload(c);
350 #ifndef NCMPC_MINI
351                 sync_highlights(c, browser.filelist);
352 #endif
353                 list_window_check_selected(browser.lw,
354                                            filelist_length(browser.filelist));
355                 file_repaint();
356                 return false;
358         case CMD_DB_UPDATE:
359                 if (c->status == NULL)
360                         return true;
362                 if (!c->status->updatingDb) {
363                         if (mpdclient_cmd_db_update(c, current_path) == 0) {
364                                 if (strcmp(current_path, "") != 0) {
365                                         char *path_locale =
366                                                 utf8_to_locale(current_path);
367                                         screen_status_printf(_("Database update of %s started"),
368                                                              path_locale);
369                                         g_free(path_locale);
370                                 } else
371                                         screen_status_printf(_("Database update started"));
372                         }
373                 } else
374                         screen_status_printf(_("Database update running..."));
375                 return true;
377         default:
378                 break;
379         }
381         if (browser_cmd(&browser, c, cmd)) {
382                 if (screen_is_visible(&screen_browse))
383                         file_repaint();
384                 return true;
385         }
387         return false;
390 const struct screen_functions screen_browse = {
391         .init = browse_init,
392         .exit = browse_exit,
393         .open = browse_open,
394         .resize = browse_resize,
395         .paint = browse_paint,
396         .cmd = browse_cmd,
397         .get_title = browse_title,
398 };
400 bool
401 screen_file_goto_song(struct mpdclient *c, const struct mpd_song *song)
403         const char *slash, *parent;
404         char *allocated = NULL;
405         bool ret;
406         int i;
408         assert(song != NULL);
409         assert(song->file != NULL);
411         if (strstr(song->file, "//") != NULL)
412                 /* an URL? */
413                 return false;
415         /* determine the song's parent directory and go there */
417         slash = strrchr(song->file, '/');
418         if (slash != NULL)
419                 parent = allocated = g_strndup(song->file, slash - song->file);
420         else
421                 parent = "";
423         ret = file_change_directory(c, NULL, parent);
424         g_free(allocated);
425         if (!ret)
426                 return false;
428         /* select the specified song */
430         i = filelist_find_song(browser.filelist, song);
431         if (i < 0)
432                 i = 0;
434         list_window_set_selected(browser.lw, i);
436         /* finally, switch to the file screen */
437         screen_switch(&screen_browse, c);
438         return true;