FS#8637 - new UI for disktidy.
[Rockbox.git] / apps / plugins / disktidy.c
blobbb4c45e97749f78a9ff1d0d49a845bfb48f74335
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 David Dent
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
22 static const struct plugin_api* rb;
23 MEM_FUNCTION_WRAPPERS(rb)
25 /* function return values */
26 enum tidy_return
28 TIDY_RETURN_OK = 0,
29 TIDY_RETURN_ERROR = 1,
30 TIDY_RETURN_USB = 2,
31 TIDY_RETURN_ABORT = 3,
34 #define MAX_TYPES 64
35 struct tidy_type {
36 char filestring[64];
37 bool directory;
38 bool remove;
39 } tidy_types[MAX_TYPES];
40 int tidy_type_count;
41 bool tidy_loaded_and_changed = false;
43 #define DEFAULT_FILES PLUGIN_APPS_DIR "/disktidy.config"
44 #define CUSTOM_FILES PLUGIN_APPS_DIR "/disktidy_custom.config"
45 void add_item(const char* name, int index)
47 rb->strcpy(tidy_types[index].filestring, name);
48 if (name[rb->strlen(name)-1] == '/')
50 tidy_types[index].directory = true;
51 tidy_types[index].filestring[rb->strlen(name)-1] = '\0';
53 else
54 tidy_types[index].directory = false;
56 static int find_file_string(const char *file, char *last_group)
58 char temp[MAX_PATH];
59 int i = 0, idx_last_group = -1;
60 bool folder = false;
61 rb->strcpy(temp, file);
62 if (temp[rb->strlen(temp)-1] == '/')
64 folder = true;
65 temp[rb->strlen(temp)-1] = '\0';
67 while (i<tidy_type_count)
69 if (!rb->strcmp(tidy_types[i].filestring, temp) &&
70 folder == tidy_types[i].directory)
71 return i;
72 else if (!rb->strcmp(tidy_types[i].filestring, last_group))
73 idx_last_group = i;
74 i++;
76 /* not found, so insert it into its group */
77 if (file[0] != '<' && idx_last_group != -1)
79 for (i=idx_last_group; i<tidy_type_count; i++)
81 if (tidy_types[i].filestring[0] == '<')
83 idx_last_group = i;
84 break;
87 /* shift items up one */
88 for (i=tidy_type_count;i>idx_last_group;i--)
90 rb->strcpy(tidy_types[i].filestring, tidy_types[i-1].filestring);
91 tidy_types[i].directory = tidy_types[i-1].directory;
92 tidy_types[i].remove = tidy_types[i-1].remove;
94 tidy_type_count++;
95 add_item(file, idx_last_group+1);
96 return idx_last_group+1;
98 return i;
101 bool tidy_load_file(const char* file)
103 int fd = rb->open(file, O_RDONLY), i;
104 char buf[MAX_PATH], *str, *remove;
105 char last_group[MAX_PATH] = "";
106 bool new;
107 if (fd < 0)
108 return false;
109 while ((tidy_type_count < MAX_TYPES) &&
110 rb->read_line(fd, buf, MAX_PATH))
112 if (rb->settings_parseline(buf, &str, &remove))
114 i = find_file_string(str, last_group);
115 new = (i >= tidy_type_count);
116 if (!rb->strcmp(remove, "yes"))
117 tidy_types[i].remove = true;
118 else tidy_types[i].remove = false;
119 if (new)
121 i = tidy_type_count;
122 add_item(str, i);
123 tidy_type_count++;
125 if (str[0] == '<')
126 rb->strcpy(last_group, str);
129 rb->close(fd);
130 return true;
133 bool tidy_remove_item(char *item, int attr)
135 int i;
136 char *file;
137 bool ret = false, rem = false;
138 for (i=0; ret == false && i < tidy_type_count; i++)
140 file = tidy_types[i].filestring;
141 if (file[rb->strlen(file)-1] == '*')
143 if (!rb->strncmp(file, item, rb->strlen(file)-1))
144 rem = true;
146 else if (!rb->strcmp(file, item))
147 rem = true;
148 if (rem)
150 if (!tidy_types[i].remove)
151 return false;
152 if (attr&ATTR_DIRECTORY)
153 ret = tidy_types[i].directory;
154 else ret = true;
157 return ret;
160 void tidy_lcd_status(const char *name, int *removed)
162 char text[24]; /* "Cleaned up nnnnn items" */
164 /* display status text */
165 rb->lcd_clear_display();
166 rb->lcd_puts(0, 0, "Working ...");
167 rb->lcd_puts(0, 1, name);
168 rb->snprintf(text, 24, "Cleaned up %d items", *removed);
169 #ifdef HAVE_LCD_BITMAP
170 rb->lcd_puts(0, 2, text);
171 #endif
172 rb->lcd_update();
175 void tidy_get_absolute_path(struct dirent *entry, char *fullname,
176 const char* name)
178 /* gets absolute path using dirent and name */
179 rb->strcpy(fullname, name);
180 if (rb->strlen(name) > 1)
182 rb->strcat(fullname, "/");
184 rb->strcat(fullname, entry->d_name);
187 enum tidy_return tidy_removedir(const char *name, int *removed)
189 /* delete directory */
190 struct dirent *entry;
191 enum tidy_return status = TIDY_RETURN_OK;
192 int button;
193 DIR *dir;
194 char fullname[MAX_PATH];
196 /* display status text */
197 tidy_lcd_status(name, removed);
199 rb->yield();
201 dir = rb->opendir(name);
202 if (dir)
204 while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0))
205 /* walk directory */
207 /* check for user input and usb connect */
208 button = rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
209 if (button == ACTION_STD_CANCEL)
211 rb->closedir(dir);
212 return TIDY_RETURN_ABORT;
214 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
216 rb->closedir(dir);
217 return TIDY_RETURN_USB;
220 rb->yield();
222 /* get absolute path */
223 tidy_get_absolute_path(entry, fullname, name);
225 if (entry->attribute & ATTR_DIRECTORY)
227 /* dir ignore "." and ".." */
228 if ((rb->strcmp(entry->d_name, ".") != 0) && \
229 (rb->strcmp(entry->d_name, "..") != 0))
231 tidy_removedir(fullname, removed);
234 else
236 /* file */
237 *removed += 1;
238 rb->remove(fullname);
241 rb->closedir(dir);
242 /* rmdir */
243 *removed += 1;
244 rb->rmdir(name);
246 else
248 status = TIDY_RETURN_ERROR;
250 return status;
253 enum tidy_return tidy_clean(const char *name, int *removed)
255 /* deletes junk files and dirs left by system */
256 struct dirent *entry;
257 enum tidy_return status = TIDY_RETURN_OK;
258 int button;
259 int del; /* has the item been deleted */
260 DIR *dir;
261 char fullname[MAX_PATH];
263 /* display status text */
264 tidy_lcd_status(name, removed);
266 rb->yield();
268 dir = rb->opendir(name);
269 if (dir)
271 while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0))
272 /* walk directory */
274 /* check for user input and usb connect */
275 button = rb->get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
276 if (button == ACTION_STD_CANCEL)
278 rb->closedir(dir);
279 return TIDY_RETURN_ABORT;
281 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
283 rb->closedir(dir);
284 return TIDY_RETURN_USB;
287 rb->yield();
289 if (entry->attribute & ATTR_DIRECTORY)
291 /* directory ignore "." and ".." */
292 if ((rb->strcmp(entry->d_name, ".") != 0) && \
293 (rb->strcmp(entry->d_name, "..") != 0))
295 del = 0;
297 /* get absolute path */
298 tidy_get_absolute_path(entry, fullname, name);
300 if (tidy_remove_item(entry->d_name, entry->attribute))
302 /* delete dir */
303 tidy_removedir(fullname, removed);
304 del = 1;
307 if (del == 0)
309 /* dir not deleted so clean it */
310 status = tidy_clean(fullname, removed);
314 else
316 /* file */
317 del = 0;
318 if (tidy_remove_item(entry->d_name, entry->attribute))
320 *removed += 1; /* increment removed files counter */
322 /* get absolute path */
323 char fullname[MAX_PATH];
324 tidy_get_absolute_path(entry, fullname, name);
326 /* delete file */
327 rb->remove(fullname);
328 del = 1;
332 rb->closedir(dir);
333 return status;
335 else
337 return TIDY_RETURN_ERROR;
341 enum plugin_status tidy_do(void)
343 /* clean disk and display num of items removed */
344 int removed = 0;
345 enum tidy_return status;
346 char text[24]; /* "Cleaned up nnnnn items" */
348 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
349 rb->cpu_boost(true);
350 #endif
352 status = tidy_clean("/", &removed);
354 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
355 rb->cpu_boost(false);
356 #endif
358 if ((status == TIDY_RETURN_OK) || (status == TIDY_RETURN_ABORT))
360 rb->lcd_clear_display();
361 rb->snprintf(text, 24, "Cleaned up %d items", removed);
362 if (status == TIDY_RETURN_ABORT)
364 rb->splash(HZ, "User aborted");
365 rb->lcd_clear_display();
367 rb->splash(HZ*2, text);
369 return status;
372 enum themable_icons get_icon(int item, void * data)
374 (void)data;
375 if (tidy_types[item].filestring[0] == '<') /* special type */
376 return Icon_Folder;
377 else if (tidy_types[item].remove)
378 return Icon_Cursor;
379 else
380 return Icon_NOICON;
383 char * get_name(int selected_item, void * data,
384 char * buffer, size_t buffer_len)
386 (void)data;
387 if (tidy_types[selected_item].directory)
389 rb->snprintf(buffer, buffer_len, "%s/",
390 tidy_types[selected_item].filestring);
391 return buffer;
393 return tidy_types[selected_item].filestring;
396 int list_action_callback(int action, struct gui_synclist *lists)
398 if (action == ACTION_STD_OK)
400 int selection = rb->gui_synclist_get_sel_pos(lists);
401 if (tidy_types[selection].filestring[0] == '<')
403 int i;
404 if (!rb->strcmp(tidy_types[selection].filestring, "< ALL >"))
406 for (i=0; i<tidy_type_count; i++)
408 if (tidy_types[i].filestring[0] != '<')
409 tidy_types[i].remove = true;
412 else if (!rb->strcmp(tidy_types[selection].filestring, "< NONE >"))
414 for (i=0; i<tidy_type_count; i++)
416 if (tidy_types[i].filestring[0] != '<')
417 tidy_types[i].remove = false;
420 else /* toggle all untill the next <> */
422 selection++;
423 while (selection < tidy_type_count &&
424 tidy_types[selection].filestring[0] != '<')
426 tidy_types[selection].remove = !tidy_types[selection].remove;
427 selection++;
431 else
432 tidy_types[selection].remove = !tidy_types[selection].remove;
433 tidy_loaded_and_changed = true;
434 return ACTION_REDRAW;
436 return action;
439 int tidy_lcd_menu(void)
441 int selection, ret = 3;
442 bool menu_quit = false;
444 MENUITEM_STRINGLIST(menu,"Disktidy Menu",NULL,"Start Cleaning",
445 "Files to Clean","Quit");
447 while (!menu_quit)
449 switch(rb->do_menu(&menu, &selection, NULL, false))
452 case 0:
453 menu_quit = true; /* start cleaning */
454 break;
456 case 1:
458 struct simplelist_info list;
459 rb->simplelist_info_init(&list, "Files to Clean", tidy_type_count, NULL);
460 list.get_icon = get_icon;
461 list.get_name = get_name;
462 list.action_callback = list_action_callback;
463 rb->simplelist_show_list(&list);
465 break;
467 default:
468 ret = 99; /* exit plugin */
469 menu_quit = true;
470 break;
473 return ret;
476 /* this is the plugin entry point */
477 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
479 enum tidy_return status;
480 int ret;
481 (void)parameter;
483 rb = api;
484 tidy_type_count = 0;
485 tidy_load_file(DEFAULT_FILES);
486 tidy_load_file(CUSTOM_FILES);
487 if (tidy_type_count == 0)
489 rb->splash(3*HZ, "Missing disktidy.config file");
490 return PLUGIN_ERROR;
492 ret = tidy_lcd_menu();
493 if (tidy_loaded_and_changed)
495 int fd = rb->creat(CUSTOM_FILES);
496 int i;
497 if (fd >= 0)
499 for(i=0;i<tidy_type_count;i++)
501 rb->fdprintf(fd, "%s%c: %s\n", tidy_types[i].filestring,
502 tidy_types[i].directory?'/':'\0',
503 tidy_types[i].remove?"yes":"no");
505 rb->close(fd);
508 if (ret == 99)
509 return PLUGIN_OK;
510 while (true)
512 status = tidy_do();
514 switch (status)
516 case TIDY_RETURN_OK:
517 return PLUGIN_OK;
518 case TIDY_RETURN_ERROR:
519 return PLUGIN_ERROR;
520 case TIDY_RETURN_USB:
521 return PLUGIN_USB_CONNECTED;
522 case TIDY_RETURN_ABORT:
523 return PLUGIN_OK;
527 if (rb->default_event_handler(rb->button_get(false)) == SYS_USB_CONNECTED)
528 return PLUGIN_USB_CONNECTED;
530 rb->yield();
533 return PLUGIN_OK;