Prepare new maemo release
[maemo-rb.git] / apps / plugins / properties.c
blob0f3ec5c4583135d2ed48583a8d10e1f7fba6edac
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Peter D'Hoye
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
25 bool its_a_dir = false;
27 char str_filename[MAX_PATH];
28 char str_dirname[MAX_PATH];
29 char str_size[64];
30 char str_dircount[64];
31 char str_filecount[64];
32 char str_date[64];
33 char str_time[64];
35 char str_title[MAX_PATH];
36 char str_artist[MAX_PATH];
37 char str_album[MAX_PATH];
38 char str_duration[32];
40 int num_properties;
42 static const char* props_file[] =
44 "[Path]", str_dirname,
45 "[Filename]", str_filename,
46 "[Size]", str_size,
47 "[Date]", str_date,
48 "[Time]", str_time,
49 "[Artist]", str_artist,
50 "[Title]", str_title,
51 "[Album]", str_album,
52 "[Duration]", str_duration,
54 static const char* props_dir[] =
56 "[Path]", str_dirname,
57 "[Subdirs]", str_dircount,
58 "[Files]", str_filecount,
59 "[Size]", str_size,
62 static const char human_size_prefix[4] = { '\0', 'K', 'M', 'G' };
63 static unsigned human_size_log(unsigned long long size)
65 const size_t n = sizeof(human_size_prefix)/sizeof(human_size_prefix[0]);
67 unsigned i;
68 /* margin set at 10K boundary: 10239 B +1 => 10 KB */
69 for(i=0; i < n-1 && size >= 10*1024; i++)
70 size >>= 10; /* div by 1024 */
72 return i;
75 static bool file_properties(char* selected_file)
77 bool found = false;
78 char tstr[MAX_PATH];
79 DIR* dir;
80 struct dirent* entry;
81 struct mp3entry id3;
83 char* ptr = rb->strrchr(selected_file, '/') + 1;
84 int dirlen = (ptr - selected_file);
85 rb->strlcpy(tstr, selected_file, dirlen + 1);
87 dir = rb->opendir(tstr);
88 if (dir)
90 while(0 != (entry = rb->readdir(dir)))
92 struct dirinfo info = rb->dir_get_info(dir, entry);
93 if(!rb->strcmp(entry->d_name, selected_file+dirlen))
95 unsigned log;
96 rb->snprintf(str_dirname, sizeof str_dirname, "%s", tstr);
97 rb->snprintf(str_filename, sizeof str_filename, "%s",
98 selected_file+dirlen);
99 log = human_size_log((unsigned long)info.size);
100 rb->snprintf(str_size, sizeof str_size, "%lu %cB",
101 ((unsigned long)info.size) >> (log*10), human_size_prefix[log]);
102 rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d",
103 ((info.wrtdate >> 9 ) & 0x7F) + 1980, /* year */
104 ((info.wrtdate >> 5 ) & 0x0F), /* month */
105 ((info.wrtdate ) & 0x1F)); /* day */
106 rb->snprintf(str_time, sizeof str_time, "%02d:%02d",
107 ((info.wrttime >> 11) & 0x1F), /* hour */
108 ((info.wrttime >> 5 ) & 0x3F)); /* minutes */
110 num_properties = 5;
112 #if (CONFIG_CODEC == SWCODEC)
113 int fd = rb->open(selected_file, O_RDONLY);
114 if (fd >= 0 &&
115 rb->get_metadata(&id3, fd, selected_file))
116 #else
117 if (!rb->mp3info(&id3, selected_file))
118 #endif
120 long dur = id3.length / 1000; /* seconds */
121 rb->snprintf(str_artist, sizeof str_artist,
122 "%s", id3.artist ? id3.artist : "");
123 rb->snprintf(str_title, sizeof str_title,
124 "%s", id3.title ? id3.title : "");
125 rb->snprintf(str_album, sizeof str_album,
126 "%s", id3.album ? id3.album : "");
127 num_properties += 3;
129 if (dur > 0)
131 if (dur < 3600)
132 rb->snprintf(str_duration, sizeof str_duration,
133 "%d:%02d", (int)(dur / 60),
134 (int)(dur % 60));
135 else
136 rb->snprintf(str_duration, sizeof str_duration,
137 "%d:%02d:%02d",
138 (int)(dur / 3600),
139 (int)(dur % 3600 / 60),
140 (int)(dur % 60));
141 num_properties++;
144 #if (CONFIG_CODEC == SWCODEC)
145 rb->close(fd);
146 #endif
147 found = true;
148 break;
151 rb->closedir(dir);
153 return found;
156 typedef struct {
157 char dirname[MAX_PATH];
158 int len;
159 unsigned int dc;
160 unsigned int fc;
161 unsigned long long bc;
162 } DPS;
164 static bool _dir_properties(DPS* dps)
166 /* recursively scan directories in search of files
167 and informs the user of the progress */
168 bool result;
169 static long lasttick=0;
170 int dirlen;
171 DIR* dir;
172 struct dirent* entry;
174 result = true;
175 dirlen = rb->strlen(dps->dirname);
176 dir = rb->opendir(dps->dirname);
177 if (!dir)
178 return false; /* open error */
180 /* walk through the directory content */
181 while(result && (0 != (entry = rb->readdir(dir))))
183 struct dirinfo info = rb->dir_get_info(dir, entry);
184 /* append name to current directory */
185 rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s",
186 entry->d_name);
188 if (info.attribute & ATTR_DIRECTORY)
190 unsigned log;
192 if (!rb->strcmp((char *)entry->d_name, ".") ||
193 !rb->strcmp((char *)entry->d_name, ".."))
194 continue; /* skip these */
196 dps->dc++; /* new directory */
197 if (*rb->current_tick - lasttick > (HZ/8))
199 lasttick = *rb->current_tick;
200 rb->lcd_clear_display();
201 rb->lcd_puts(0,0,"SCANNING...");
202 rb->lcd_puts(0,1,dps->dirname);
203 rb->lcd_puts(0,2,entry->d_name);
204 rb->lcd_putsf(0,3,"Directories: %d", dps->dc);
205 rb->lcd_putsf(0,4,"Files: %d", dps->fc);
206 log = human_size_log(dps->bc);
207 rb->lcd_putsf(0,5,"Size: %lu %cB", (unsigned long)(dps->bc >> (10*log)),
208 human_size_prefix[log]);
209 rb->lcd_update();
212 /* recursion */
213 result = _dir_properties(dps);
215 else
217 dps->fc++; /* new file */
218 dps->bc += info.size;
220 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
221 result = false;
222 rb->yield();
224 rb->closedir(dir);
225 return result;
228 static bool dir_properties(char* selected_file)
230 unsigned log;
231 DPS dps = {
232 .len = MAX_PATH,
233 .dc = 0,
234 .fc = 0,
235 .bc = 0,
237 rb->strlcpy(dps.dirname, selected_file, MAX_PATH);
239 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
240 rb->cpu_boost(true);
241 #endif
243 if(false == _dir_properties(&dps))
244 return false;
246 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
247 rb->cpu_boost(false);
248 #endif
250 rb->strlcpy(str_dirname, selected_file, MAX_PATH);
251 rb->snprintf(str_dircount, sizeof str_dircount, "%d", dps.dc);
252 rb->snprintf(str_filecount, sizeof str_filecount, "%d", dps.fc);
253 log = human_size_log(dps.bc);
254 rb->snprintf(str_size, sizeof str_size, "%ld %cB",
255 (long) (dps.bc >> (log*10)), human_size_prefix[log]);
256 num_properties = 4;
257 return true;
260 static const char * get_props(int selected_item, void* data,
261 char *buffer, size_t buffer_len)
263 (void)data;
264 if(its_a_dir)
266 if(selected_item >= (int)(sizeof(props_dir) / sizeof(props_dir[0])))
268 rb->strlcpy(buffer, "ERROR", buffer_len);
270 else
272 rb->strlcpy(buffer, props_dir[selected_item], buffer_len);
275 else
277 if(selected_item >= (int)(sizeof(props_file) / sizeof(props_file[0])))
279 rb->strlcpy(buffer, "ERROR", buffer_len);
281 else
283 rb->strlcpy(buffer, props_file[selected_item], buffer_len);
286 return buffer;
289 enum plugin_status plugin_start(const void* parameter)
291 struct gui_synclist properties_lists;
292 int button;
293 bool quit = false, usb = false;
294 char file[MAX_PATH];
295 if(!parameter) return PLUGIN_ERROR;
296 rb->strcpy(file, (const char *) parameter);
297 #ifdef HAVE_TOUCHSCREEN
298 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
299 #endif
301 /* determine if it's a file or a directory */
302 bool found = false;
303 DIR* dir;
304 struct dirent* entry;
305 char* ptr = rb->strrchr(file, '/') + 1;
306 int dirlen = (ptr - file);
307 rb->strlcpy(str_dirname, file, dirlen + 1);
309 dir = rb->opendir(str_dirname);
310 if (dir)
312 while(0 != (entry = rb->readdir(dir)))
314 if(!rb->strcmp(entry->d_name, file+dirlen))
316 struct dirinfo info = rb->dir_get_info(dir, entry);
317 its_a_dir = info.attribute & ATTR_DIRECTORY ? true : false;
318 found = true;
319 break;
322 rb->closedir(dir);
324 /* now we know if it's a file or a dir or maybe something failed */
326 if(!found)
328 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
329 rb->splashf(0, "File/Dir not found: %s", file);
330 rb->action_userabort(TIMEOUT_BLOCK);
331 return PLUGIN_OK;
334 /* get the info depending on its_a_dir */
335 if(!(its_a_dir ? dir_properties(file) : file_properties(file)))
337 /* something went wrong (to do: tell user what it was (nesting,...) */
338 rb->splash(0, "Failed to gather information");
339 rb->action_userabort(TIMEOUT_BLOCK);
340 return PLUGIN_OK;
343 #ifdef HAVE_LCD_BITMAP
344 FOR_NB_SCREENS(i)
345 rb->viewportmanager_theme_enable(i, true, NULL);
346 #endif
348 rb->gui_synclist_init(&properties_lists, &get_props, file, false, 2, NULL);
349 rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
350 "Directory properties" :
351 "File properties", NOICON);
352 rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
353 rb->gui_synclist_set_nb_items(&properties_lists, num_properties * 2);
354 rb->gui_synclist_limit_scroll(&properties_lists, true);
355 rb->gui_synclist_select_item(&properties_lists, 0);
356 rb->gui_synclist_draw(&properties_lists);
358 while(!quit)
360 button = rb->get_action(CONTEXT_LIST, HZ);
361 /* HZ so the status bar redraws corectly */
362 if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_ON))
363 continue;
364 switch(button)
366 case ACTION_STD_CANCEL:
367 quit = true;
368 break;
369 default:
370 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
372 quit = true;
373 usb = true;
375 break;
379 #ifdef HAVE_LCD_BITMAP
380 FOR_NB_SCREENS(i)
381 rb->viewportmanager_theme_undo(i, false);
382 #endif
384 return usb? PLUGIN_USB_CONNECTED: PLUGIN_OK;