Index: apps/plugins/CATEGORIES =================================================================== --- apps/plugins/CATEGORIES (revision 21072) +++ apps/plugins/CATEGORIES (working copy) @@ -99,6 +99,7 @@ test_viewports,apps test_greylib_bitmap_scale,viewers text_editor,apps +theme_remove,viewers vbrfix,viewers video,viewers viewer,viewers Index: apps/plugins/theme_remove.c =================================================================== --- apps/plugins/theme_remove.c (revision 0) +++ apps/plugins/theme_remove.c (revision 0) @@ -0,0 +1,416 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +/* + * TODO: + * - implement option to remove file if any other theme dosen't use it + * - save options + */ +#include "plugin.h" + +PLUGIN_HEADER + +/* taken from apps/gui/wps_parser.c */ +#define WPS_DEFAULTCFG WPS_DIR "/rockbox_default.wps" +#define RWPS_DEFAULTCFG WPS_DIR "/rockbox_default.rwps" + +enum remove_option { + ALWAYS_REMOVE, + NEVER_REMOVE, + ASK, + NUM_REMOVE_OPTION +}; +struct setting { + const char *name; + const char *prefix, *suffix; + char value[MAX_PATH]; + enum remove_option option; + int (*func)(struct setting *); +}; + +static int remove_wps(struct setting *); +static int remove_icons(struct setting *setting); + +struct setting remove_list[] = { + { "font", FONT_DIR "/", ".fnt", "", NEVER_REMOVE, NULL }, + { "wps", WPS_DIR "/", ".wps", "", ALWAYS_REMOVE, remove_wps }, + { "rwps", WPS_DIR "/", ".rwps", "", ALWAYS_REMOVE, remove_wps }, + { "backdrop", BACKDROP_DIR "/", ".bmp", "", ALWAYS_REMOVE, NULL }, + { "iconset", ICON_DIR "/", ".bmp", "", ASK, NULL }, + { "viewers iconset", ICON_DIR "/", ".bmp", "", ASK, remove_icons }, + { "remote iconset", ICON_DIR "/", ".bmp", "", ASK, NULL }, + { "remote viewers iconset", ICON_DIR "/", ".bmp", "", ASK, NULL }, + { "filetype colours", THEME_DIR "/", ".colours", "", ASK, NULL }, +}; +static const int nb_remove_list = sizeof(remove_list)/sizeof(*remove_list); +static char filename[MAX_PATH]; + +static int printf(const char *fmt, ...) +{ + static int print_line = 0; + static char print_buf[MAX_PATH*2]; + va_list ap; + + va_start(ap, fmt); + rb->vsnprintf(print_buf,sizeof(print_buf), fmt, ap); + va_end(ap); + + DEBUGF("%s\n", print_buf); +#ifdef HAVE_LCD_CHARCELLS + rb->lcd_puts(0, print_line++, print_buf); + if (print_line >= LCD_HEIGHT) + print_line = 0; + rb->lcd_update(); +#else + struct font* pf = rb->font_get(FONT_UI); + unsigned short ch; + int width = 0; + int nb_lines = LCD_HEIGHT/pf->height; + char *p = print_buf, *str = print_buf; + + do { + if (*str == '\n') + { + *str++ = 0; + width = LCD_WIDTH; + } + else + { + str = (char *) rb->utf8decode(str, &ch); + width += rb->font_get_width(pf,ch); + } + if (ch == 0 || width >= LCD_WIDTH) + { + width = 0; + rb->lcd_puts(0, print_line++, p); + p = str; + if (print_line >= nb_lines) + print_line = 0; + } + } while (ch != 0); + + rb->lcd_puts(0, print_line, " "); + rb->lcd_update(); +#endif + + return 0; +} + +/* taken from apps/onplay.c */ +/* helper function to remove a non-empty directory */ +static int remove_dir(char* dirname, int len) +{ + int result = 0; + DIR* dir; + int dirlen = rb->strlen(dirname); + + dir = rb->opendir(dirname); + if (!dir) + return -1; /* open error */ + + while(true) + { + struct dirent* entry; + /* walk through the directory content */ + entry = rb->readdir(dir); + if (!entry) + break; + + dirname[dirlen] ='\0'; + + /* append name to current directory */ + rb->snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name); + if (entry->attribute & ATTR_DIRECTORY) + { /* remove a subdirectory */ + if (!rb->strcmp((char *)entry->d_name, ".") || + !rb->strcmp((char *)entry->d_name, "..")) + continue; /* skip these */ + + /* inform the user which dir we're deleting */ + + result = remove_dir(dirname, len); /* recursion */ + if (result) + break; /* or better continue, delete what we can? */ + } + else + { /* remove a file */ + result = rb->remove(dirname); + } + if (ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) + { + printf("Canceled"); + result = -1; + break; + } + } + rb->closedir(dir); + + if (!result) + { /* remove the now empty directory */ + dirname[dirlen] = '\0'; /* terminate to original length */ + + result = rb->rmdir(dirname); + printf("Removed %s", dirname); + } + + return result; +} + +static int remove_wps(struct setting *setting) +{ + char bmpdir[MAX_PATH]; + char *p; + rb->strcpy(bmpdir, setting->value); + p = rb->strrchr(bmpdir, '.'); + if (p) *p = 0; + if (!rb->dir_exists(bmpdir)) + return 0; + return remove_dir(bmpdir, MAX_PATH); +} + +static int remove_icons(struct setting *setting) +{ + char path[MAX_PATH]; + char *p; + rb->strcpy(path, setting->value); + p = rb->strrchr(path, '.'); + rb->strncpy(p, ".icons", path+MAX_PATH-p); + + if (!rb->file_exists(path)) + { + return 0; + } + if (rb->remove(path)) + { + printf("Failed: %s", path); + return 1; + } + printf("Removed: %s", path); + return 0; +} + +static char font_file[MAX_PATH]; +static bool is_deny_file(const char *file) +{ + const char *deny_files[] = { + WPS_DEFAULTCFG, + RWPS_DEFAULTCFG, + font_file, + NULL + }; + const char **p = deny_files; + while ( *p ) + { + if (!rb->strcmp(file, *p)) + return true; + p++; + } + return false; +} + +static int remove_file(struct setting *setting) +{ + if (!rb->file_exists(setting->value)) + { + printf("Not exists: %s", setting->value); + return 0; + } + if (is_deny_file(setting->value)) + { + printf("Denied: %s", setting->value); + return 0; + } + switch (setting->option) + { + case ALWAYS_REMOVE: + break; + case NEVER_REMOVE: + printf("Skipped: %s", setting->value); + return 0; + break; + case ASK: + default: + { + const char *message_lines[] = { "Delete?", setting->value }; + const struct text_message text_message = { message_lines, 2 }; + if (rb->gui_syncyesno_run(&text_message, NULL, NULL) != YESNO_YES) + { + printf("Skipped: %s", setting->value); + return 0; + } + } + break; + } + if (rb->remove(setting->value)) + { + printf("Failed: %s", setting->value); + return 1; + } + if (setting->func && setting->func(setting)) + return 1; + printf("Removed: %s", setting->value); + return 0; +} +static int remove_theme(void) +{ + static char line[MAX_PATH]; + int fd; + int i, k=0; + char *name, *value; + + /* initialize for safe */ + for (i=0; iopen(filename, O_RDONLY); + if (fd < 0) return fd; + while (rb->read_line(fd, line, sizeof(line)) > 0) + { + if (ACTION_STD_CANCEL == rb->get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) + { + printf("Canceled"); + rb->close(fd); + return -1; + } + if (!rb->settings_parseline(line, &name, &value)) + continue; + /* remove trailing spaces. */ + char *p = value+rb->strlen(value)-1; + while (*p == ' ') *p-- = 0; + if (*value == 0 || !rb->strcmp(value, "-")) + continue; + for (i=0; istrcmp(name, setting->name)) + { + /* set full path of value. */ + if (rb->strncasecmp(value, setting->prefix, + rb->strlen(setting->prefix))) + rb->snprintf(setting->value, MAX_PATH, "%s%s", + setting->prefix, value); + else + rb->strncpy(setting->value, value, MAX_PATH); + int len1 = rb->strlen(setting->value); + int len2 = rb->strlen(setting->suffix); + if (rb->strcasecmp(setting->value+len1-len2, setting->suffix)) + rb->strncpy(&setting->value[len1], setting->suffix, MAX_PATH-len1); + /* now remove file. */ + if (remove_file(setting)) + { + rb->close(fd); + return 0; + } + k++; + rb->sleep(HZ/2); + break; + } + } + } + rb->close(fd); + /* only delete setting files in theme directory */ + if (rb->strncasecmp(filename, THEME_DIR "/", sizeof(THEME_DIR "/")-1)) + { + printf("Skipped: %s", filename); + return k; + } + if (rb->remove(filename)) + { + printf("Failed: %s", filename); + return 0; + } + printf("Removed: %s", filename); + k++; + return k; +} + +static bool option_menu(void) +{ + MENUITEM_STRINGLIST(option_menu, "Remove Options", NULL, + /* same order as remove_list */ + "font", "wps", "remote wps", + "backdrop", "iconset", "viewers iconset", + "remote iconset", "remote viewers iconset", + "filetype colours"); + struct opt_items remove_names[] = { + {"Always Remove", -1}, {"Never Remove", -1}, + {"Ask", -1}, + }; + int selected = 0; + while (1) + { + selected = rb->do_menu(&option_menu, &selected, NULL, false); + if (selected >= 0 && selected < nb_remove_list) + { + struct setting *setting = &remove_list[selected]; + if (rb->set_option(setting->name, &setting->option, INT, + remove_names, NUM_REMOVE_OPTION, NULL)) + return true; + } + else if (selected == MENU_ATTACHED_USB) + return true; + else + return false; + } + return false; +} + +enum plugin_status plugin_start(const void* parameter) +{ + MENUITEM_STRINGLIST(menu, "Theme Remove", NULL, + "Remove Theme", "Remove Options"); + int selected=0; + + if (!parameter) + return PLUGIN_ERROR; + rb->snprintf(font_file, MAX_PATH, FONT_DIR "/%s.fnt", rb->global_settings->font_file); + rb->strncpy(filename, parameter, MAX_PATH); + filename[MAX_PATH-1] = 0; + if (!rb->file_exists(filename)) + { + rb->splash(HZ, "File open error!"); + return PLUGIN_ERROR; + } + while (1) + { + switch (rb->do_menu(&menu, &selected, NULL, false)) + { + case 0: + if (remove_theme() > 0) + printf("Successfully removed!"); + else + printf("Remove failure"); + printf("Press any key to exit."); + rb->button_clear_queue(); + rb->button_get(true); + return PLUGIN_OK; + break; + case 1: + if (option_menu()) + return PLUGIN_USB_CONNECTED; + break; + case MENU_ATTACHED_USB: + return PLUGIN_USB_CONNECTED; + break; + default: + return PLUGIN_OK; + break; + } + } + return PLUGIN_OK; +} Index: apps/plugins/SOURCES =================================================================== --- apps/plugins/SOURCES (revision 21072) +++ apps/plugins/SOURCES (working copy) @@ -16,6 +16,7 @@ sort.c stats.c stopwatch.c +theme_remove.c vbrfix.c viewer.c #ifdef HAVE_BACKLIGHT Index: apps/plugins/viewers.config =================================================================== --- apps/plugins/viewers.config (revision 21072) +++ apps/plugins/viewers.config (working copy) @@ -49,6 +49,7 @@ tzx,viewers/zxbox,12 z80,viewers/zxbox,12 ppm,viewers/ppmviewer,2 +cfg,viewers/theme_remove,- *,viewers/properties,- colours,apps/text_editor,11 ssg,games/superdom,-