when changing settings from the Talk and Voice window also update the main widgets...
[Rockbox.git] / apps / plugins / properties.c
blob0811b00ed3dce35dd87123daed495b9004b711fc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Peter D'Hoye
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
21 PLUGIN_HEADER
23 static struct plugin_api* rb;
25 MEM_FUNCTION_WRAPPERS(rb);
27 bool its_a_dir = false;
29 char str_filename[MAX_PATH];
30 char str_dirname[MAX_PATH];
31 char str_size[64];
32 char str_dircount[64];
33 char str_filecount[64];
34 char str_date[64];
35 char str_time[64];
37 char str_title[MAX_PATH];
38 char str_artist[MAX_PATH];
39 char str_album[MAX_PATH];
41 int num_properties;
43 static char* filesize2string(long long size, char* pstr, int len)
45 /* margin set at 10K boundary: 10239 B +1 => 10 KB
46 routine below is 200 bytes smaller than cascaded if/else :)
47 not using build-in function because of huge values (long long) */
48 const char* kgb[4] = { "B", "KB", "MB", "GB" };
49 int i = 0;
50 while(true)
52 if((size < 10240) || (i > 2))
54 /* depends on the order in the above array */
55 rb->snprintf(pstr, len, "%ld %s", (long)size, kgb[i]);
56 break;
58 size >>= 10; /* div by 1024 */
59 i++;
61 return pstr;
64 static bool file_properties(char* selected_file)
66 bool found = false;
67 char tstr[MAX_PATH];
68 DIR* dir;
69 struct dirent* entry;
70 struct mp3entry id3;
72 char* ptr = rb->strrchr(selected_file, '/') + 1;
73 int dirlen = (ptr - selected_file);
74 rb->strncpy(tstr, selected_file, dirlen);
75 tstr[dirlen] = 0;
77 dir = rb->opendir(tstr);
78 if (dir)
80 while(0 != (entry = rb->readdir(dir)))
82 if(!rb->strcmp(entry->d_name, selected_file+dirlen))
84 rb->snprintf(str_dirname, sizeof str_dirname, "Path: %s",
85 tstr);
86 rb->snprintf(str_filename, sizeof str_filename, "Name: %s",
87 selected_file+dirlen);
88 rb->snprintf(str_size, sizeof str_size, "Size: %s",
89 filesize2string(entry->size, tstr, sizeof tstr));
90 rb->snprintf(str_date, sizeof str_date, "Date: %04d/%02d/%02d",
91 ((entry->wrtdate >> 9 ) & 0x7F) + 1980, /* year */
92 ((entry->wrtdate >> 5 ) & 0x0F), /* month */
93 ((entry->wrtdate ) & 0x1F)); /* day */
94 rb->snprintf(str_time, sizeof str_time, "Time: %02d:%02d",
95 ((entry->wrttime >> 11) & 0x1F), /* hour */
96 ((entry->wrttime >> 5 ) & 0x3F)); /* minutes */
98 num_properties = 5;
100 #if (CONFIG_CODEC == SWCODEC)
101 int fd = rb->open(selected_file, O_RDONLY);
102 if (fd >= 0 &&
103 rb->get_metadata(&id3, fd, selected_file))
104 #else
105 if (!rb->mp3info(&id3, selected_file))
106 #endif
108 rb->snprintf(str_artist, sizeof str_artist,
109 "Artist: %s", id3.artist ? id3.artist : "");
110 rb->snprintf(str_title, sizeof str_title,
111 "Title: %s", id3.title ? id3.title : "");
112 rb->snprintf(str_album, sizeof str_album,
113 "Album: %s", id3.album ? id3.album : "");
114 num_properties += 3;
116 #if (CONFIG_CODEC == SWCODEC)
117 rb->close(fd);
118 #endif
119 found = true;
120 break;
123 rb->closedir(dir);
125 return found;
128 typedef struct {
129 char dirname[MAX_PATH];
130 int len;
131 unsigned int dc;
132 unsigned int fc;
133 long long bc;
134 char tstr[64];
135 char tstr2[64];
136 } DPS;
138 static bool _dir_properties(DPS* dps)
140 /* recursively scan directories in search of files
141 and informs the user of the progress */
142 bool result;
143 int dirlen;
144 DIR* dir;
145 struct dirent* entry;
147 result = true;
148 dirlen = rb->strlen(dps->dirname);
149 dir = rb->opendir(dps->dirname);
150 if (!dir)
151 return false; /* open error */
153 /* walk through the directory content */
154 while(result && (0 != (entry = rb->readdir(dir))))
156 /* append name to current directory */
157 rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s",
158 entry->d_name);
160 if (entry->attribute & ATTR_DIRECTORY)
162 if (!rb->strcmp((char *)entry->d_name, ".") ||
163 !rb->strcmp((char *)entry->d_name, ".."))
164 continue; /* skip these */
166 dps->dc++; /* new directory */
167 rb->lcd_clear_display();
168 rb->lcd_puts(0,0,"SCANNING...");
169 rb->lcd_puts(0,1,dps->dirname);
170 rb->lcd_puts(0,2,entry->d_name);
171 rb->snprintf(dps->tstr, 64, "Directories: %d", dps->dc);
172 rb->lcd_puts(0,3,dps->tstr);
173 rb->snprintf(dps->tstr, 64, "Files: %d", dps->fc);
174 rb->lcd_puts(0,4,dps->tstr);
175 rb->snprintf(dps->tstr, 64, "Size: %s",
176 filesize2string(dps->bc, dps->tstr2, 64));
177 rb->lcd_puts(0,5,dps->tstr);
178 rb->lcd_update();
180 /* recursion */
181 result = _dir_properties(dps);
183 else
185 dps->fc++; /* new file */
186 dps->bc += entry->size;
188 if(ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
189 result = false;
190 rb->yield();
192 rb->closedir(dir);
193 return result;
196 static bool dir_properties(char* selected_file)
198 DPS dps;
199 char tstr[64];
200 rb->strncpy(dps.dirname, selected_file, MAX_PATH);
201 dps.len = MAX_PATH;
202 dps.dc = 0;
203 dps.fc = 0;
204 dps.bc = 0;
205 if(false == _dir_properties(&dps))
206 return false;
208 rb->snprintf(str_dirname, MAX_PATH, selected_file);
209 rb->snprintf(str_dircount, sizeof str_dircount, "Subdirs: %d", dps.dc);
210 rb->snprintf(str_filecount, sizeof str_filecount, "Files: %d", dps.fc);
211 rb->snprintf(str_size, sizeof str_size, "Size: %s",
212 filesize2string(dps.bc, tstr, sizeof tstr));
213 num_properties = 4;
214 return true;
217 char * get_props(int selected_item, void* data, char *buffer)
219 (void)data;
221 switch(selected_item)
223 case 0:
224 rb->strcpy(buffer, str_dirname);
225 break;
226 case 1:
227 rb->strcpy(buffer, its_a_dir ? str_dircount : str_filename);
228 break;
229 case 2:
230 rb->strcpy(buffer, its_a_dir ? str_filecount : str_size);
231 break;
232 case 3:
233 rb->strcpy(buffer, its_a_dir ? str_size : str_date);
234 break;
235 case 4:
236 rb->strcpy(buffer, its_a_dir ? "" : str_time);
237 break;
238 case 5:
239 rb->strcpy(buffer, its_a_dir ? "" : str_artist);
240 break;
241 case 6:
242 rb->strcpy(buffer, its_a_dir ? "" : str_title);
243 break;
244 case 7:
245 rb->strcpy(buffer, its_a_dir ? "" : str_album);
246 break;
247 default:
248 rb->strcpy(buffer, "ERROR");
249 break;
251 return buffer;
254 enum plugin_status plugin_start(struct plugin_api* api, void* file)
256 rb = api;
257 struct gui_synclist properties_lists;
258 int button;
259 bool prev_show_statusbar;
260 bool quit = false;
262 /* determine if it's a file or a directory */
263 bool found = false;
264 DIR* dir;
265 struct dirent* entry;
266 char* ptr = rb->strrchr((char*)file, '/') + 1;
267 int dirlen = (ptr - (char*)file);
268 rb->strncpy(str_dirname, (char*)file, dirlen);
269 str_dirname[dirlen] = 0;
271 dir = rb->opendir(str_dirname);
272 if (dir)
274 while(0 != (entry = rb->readdir(dir)))
276 if(!rb->strcmp(entry->d_name, file+dirlen))
278 its_a_dir = entry->attribute & ATTR_DIRECTORY ? true : false;
279 found = true;
280 break;
283 rb->closedir(dir);
285 /* now we know if it's a file or a dir or maybe something failed */
287 if(!found)
289 /* weird: we couldn't find the entry. This Should Never Happen (TM) */
290 rb->splash(0, "File/Dir not found: %s", (char*)file);
291 rb->action_userabort(TIMEOUT_BLOCK);
292 return PLUGIN_OK;
295 /* get the info depending on its_a_dir */
296 if(!(its_a_dir ? dir_properties((char*)file):file_properties((char*)file)))
298 /* something went wrong (to do: tell user what it was (nesting,...) */
299 rb->splash(0, "Failed to gather information");
300 rb->action_userabort(TIMEOUT_BLOCK);
301 return PLUGIN_OK;
304 /* prepare the list for the user */
305 prev_show_statusbar = rb->global_settings->statusbar;
306 rb->global_settings->statusbar = false;
308 rb->gui_synclist_init(&properties_lists, &get_props, file, false, 1);
309 rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
310 "Directory properties" :
311 "File properties", NOICON);
312 rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
313 rb->gui_synclist_set_nb_items(&properties_lists, num_properties);
314 rb->gui_synclist_limit_scroll(&properties_lists, true);
315 rb->gui_synclist_select_item(&properties_lists, 0);
316 rb->gui_synclist_draw(&properties_lists);
318 while(!quit)
320 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
321 if (rb->gui_synclist_do_button(&properties_lists,&button,LIST_WRAP_ON))
322 continue;
323 switch(button)
325 case ACTION_STD_CANCEL:
326 quit = true;
327 break;
328 default:
329 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
331 rb->global_settings->statusbar = prev_show_statusbar;
332 return PLUGIN_USB_CONNECTED;
336 rb->global_settings->statusbar = prev_show_statusbar;
338 return PLUGIN_OK;