summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/filetypes.c2
-rw-r--r--apps/lang/english.lang14
-rw-r--r--apps/onplay.c13
-rw-r--r--apps/plugin.c8
-rw-r--r--apps/plugin.h14
-rw-r--r--apps/plugins/SOURCES1
-rw-r--r--apps/plugins/properties.c359
-rw-r--r--apps/plugins/viewers.config1
-rw-r--r--docs/CREDITS1
9 files changed, 410 insertions, 3 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 0aceb74..573e640 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -56,7 +56,7 @@
#endif
/* string buffer length */
-#define STRING_BUFFER_SIZE 512
+#define STRING_BUFFER_SIZE 548
/* number of bytes for the binary icon */
#define ICON_LENGTH 6
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 83543d3..9dee957 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -10358,3 +10358,17 @@
*: "AGC maximum gain"
</voice>
</phrase>
+<phrase>
+ id: LANG_PROPERTIES
+ desc: browser file/dir properties
+ user:
+ <source>
+ *: "Properties"
+ </source>
+ <dest>
+ *: "Properties"
+ </dest>
+ <voice>
+ *: "Properties"
+ </voice>
+</phrase>
diff --git a/apps/onplay.c b/apps/onplay.c
index 59fa8ca..90117ea 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -560,6 +560,14 @@ bool create_dir(void)
return true;
}
+static bool properties(void)
+{
+ if(PLUGIN_USB_CONNECTED == filetype_load_plugin("properties",
+ selected_file))
+ onplay_result = ONPLAY_RELOAD_DIR;
+ return false;
+}
+
/* Store the current selection in the clipboard */
static bool clipboard_clip(bool copy)
{
@@ -966,7 +974,12 @@ int onplay(char* file, int attr, int from)
items[i].desc = ID2P(LANG_CREATE_DIR);
items[i].function = create_dir;
i++;
+
+ items[i].desc = ID2P(LANG_PROPERTIES);
+ items[i].function = properties;
+ i++;
}
+
if (context == CONTEXT_WPS)
{
#ifdef HAVE_PITCHSCREEN
diff --git a/apps/plugin.c b/apps/plugin.c
index e74e4a7..268fee5 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -192,6 +192,7 @@ static const struct plugin_api rockbox_api = {
gui_synclist_scroll_left,
#endif
gui_synclist_do_button,
+ gui_synclist_set_title,
/* button */
button_get,
@@ -229,6 +230,13 @@ static const struct plugin_api rockbox_api = {
PREFIX(readdir),
PREFIX(mkdir),
PREFIX(rmdir),
+
+ /* dir, cached */
+#ifdef HAVE_DIRCACHE
+ opendir_cached,
+ readdir_cached,
+ closedir_cached,
+#endif
/* kernel/ system */
PREFIX(sleep),
diff --git a/apps/plugin.h b/apps/plugin.h
index ba0fdf0..22f6b97 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -37,6 +37,9 @@
#include "config.h"
#include "system.h"
#include "dir.h"
+#ifndef SIMULATOR
+#include "dircache.h"
+#endif
#include "kernel.h"
#include "thread.h"
#include "button.h"
@@ -107,12 +110,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 37
+#define PLUGIN_API_VERSION 38
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 37
+#define PLUGIN_MIN_API_VERSION 38
/* plugin return codes */
enum plugin_status {
@@ -281,6 +284,7 @@ struct plugin_api {
#endif
unsigned (*gui_synclist_do_button)(struct gui_synclist * lists,
unsigned button,enum list_wrap wrap);
+ void (*gui_synclist_set_title)(struct gui_synclist *lists, char* title, ICON icon);
/* button */
long (*button_get)(bool block);
@@ -318,6 +322,12 @@ struct plugin_api {
struct dirent* (*PREFIX(readdir))(DIR* dir);
int (*PREFIX(mkdir))(const char *name, int mode);
int (*PREFIX(rmdir))(const char *name);
+ /* dir, cached */
+#ifdef HAVE_DIRCACHE
+ DIRCACHED* (*opendir_cached)(const char* name);
+ struct dircache_entry* (*readdir_cached)(DIRCACHED* dir);
+ int (*closedir_cached)(DIRCACHED* dir);
+#endif
/* kernel/ system */
void (*PREFIX(sleep))(int ticks);
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 63cfa8a..cf34127 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -7,6 +7,7 @@ dict.c
firmware_flash.c
logo.c
mosaique.c
+properties.c
random_folder_advance_config.c
#if (LCD_WIDTH != 240) && ((LCD_WIDTH != 128) || (LCD_HEIGHT != 64)) && !defined(SANSA_E200)
rockblox.c
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
new file mode 100644
index 0000000..458ee22
--- /dev/null
+++ b/apps/plugins/properties.c
@@ -0,0 +1,359 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Peter D'Hoye
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "plugin.h"
+
+PLUGIN_HEADER
+
+static struct plugin_api* rb;
+
+bool its_a_dir = false;
+
+char str_filename[MAX_PATH];
+char str_dirname[MAX_PATH];
+char str_size[64];
+char str_dircount[64];
+char str_filecount[64];
+char str_date[64];
+char str_time[64];
+
+static char* filesize2string(long long size, char* pstr, int len)
+{
+ /* margin set at 10K boundary: 10239 B +1 => 10 KB
+ routine below is 200 bytes smaller than cascaded if/else :)
+ not using build-in function because of huge values (long long) */
+ const char* kgb[4] = { "B", "KB", "MB", "GB" };
+ int i = 0;
+ while(true)
+ {
+ if((size < 10240) || (i > 2))
+ {
+ /* depends on the order in the above array */
+ rb->snprintf(pstr, len, "%ld %s", (long)size, kgb[i]);
+ break;
+ }
+ size >>= 10; /* div by 1024 */
+ i++;
+ }
+ return pstr;
+}
+
+static bool file_properties(char* selected_file)
+{
+ bool found = false;
+ char tstr[MAX_PATH];
+#ifdef HAVE_DIRCACHE
+ DIRCACHED* dir;
+ struct dircache_entry* entry;
+#else
+ DIR* dir;
+ struct dirent* entry;
+#endif
+ char* ptr = rb->strrchr(selected_file, '/') + 1;
+ int dirlen = (ptr - selected_file);
+ rb->strncpy(tstr, selected_file, dirlen);
+ tstr[dirlen] = 0;
+
+#ifdef HAVE_DIRCACHE
+ dir = rb->opendir_cached(tstr);
+#else
+ dir = rb->opendir(tstr);
+#endif
+ if (dir)
+ {
+#ifdef HAVE_DIRCACHE
+ while(0 != (entry = rb->readdir_cached(dir)))
+#else
+ while(0 != (entry = rb->readdir(dir)))
+#endif
+ {
+ if(!rb->strcmp(entry->d_name, selected_file+dirlen))
+ {
+ rb->snprintf(str_dirname, sizeof str_dirname, "Path: %s",
+ tstr);
+ rb->snprintf(str_filename, sizeof str_filename, "Name: %s",
+ selected_file+dirlen);
+ rb->snprintf(str_size, sizeof str_size, "Size: %s",
+ filesize2string(entry->size, tstr, sizeof tstr));
+ rb->snprintf(str_date, sizeof str_date, "Date: %04d/%02d/%02d",
+ ((entry->wrtdate >> 9 ) & 0x7F) + 1980, /* year */
+ ((entry->wrtdate >> 5 ) & 0x0F), /* month */
+ ((entry->wrtdate ) & 0x1F)); /* day */
+ rb->snprintf(str_time, sizeof str_time, "Time: %02d:%02d",
+ ((entry->wrttime >> 11) & 0x1F), /* hour */
+ ((entry->wrttime >> 5 ) & 0x3F)); /* minutes */
+ found = true;
+ break;
+ }
+ }
+#ifdef HAVE_DIRCACHE
+ rb->closedir_cached(dir);
+#else
+ rb->closedir(dir);
+#endif
+ }
+ return found;
+}
+
+typedef struct {
+ char dirname[MAX_PATH];
+ int len;
+ unsigned int dc;
+ unsigned int fc;
+ long long bc;
+ char tstr[64];
+ char tstr2[64];
+} DPS;
+
+static bool _dir_properties(DPS* dps)
+{
+ /* recursively scan directories in search of files
+ and informs the user of the progress */
+ bool result;
+ int dirlen;
+#ifdef HAVE_DIRCACHE
+ DIRCACHED* dir;
+ struct dircache_entry* entry;
+#else
+ DIR* dir;
+ struct dirent* entry;
+#endif
+
+ result = 0;
+ dirlen = rb->strlen(dps->dirname);
+#ifdef HAVE_DIRCACHE
+ dir = rb->opendir_cached(dps->dirname);
+#else
+ dir = rb->opendir(dps->dirname);
+#endif
+ if (!dir)
+ return false; /* open error */
+
+ /* walk through the directory content */
+#ifdef HAVE_DIRCACHE
+ while((!result) && (0 != (entry = rb->readdir_cached(dir))))
+#else
+ while((!result) && (0 != (entry = rb->readdir(dir))))
+#endif
+ {
+ /* append name to current directory */
+ rb->snprintf(dps->dirname+dirlen, dps->len-dirlen, "/%s",
+ entry->d_name);
+
+ if (entry->attribute & ATTR_DIRECTORY)
+ {
+ if (!rb->strcmp((char *)entry->d_name, ".") ||
+ !rb->strcmp((char *)entry->d_name, ".."))
+ continue; /* skip these */
+
+ dps->dc++; /* new directory */
+ rb->lcd_puts(0,0,"SCANNING...");
+ rb->lcd_clear_display();
+ rb->lcd_puts(0,1,dps->dirname);
+ rb->lcd_puts(0,2,entry->d_name);
+ rb->snprintf(dps->tstr, 64, "Directories: %d", dps->dc);
+ rb->lcd_puts(0,3,dps->tstr);
+ rb->snprintf(dps->tstr, 64, "Files: %d", dps->fc);
+ rb->lcd_puts(0,4,dps->tstr);
+ rb->snprintf(dps->tstr, 64, "Size: %s",
+ filesize2string(dps->bc, dps->tstr2, 64));
+ rb->lcd_puts(0,5,dps->tstr);
+ rb->lcd_update();
+
+ /* recursion */
+ result = _dir_properties(dps);
+ if(rb->get_action(CONTEXT_TREE,TIMEOUT_NOBLOCK))
+ result = false;
+ }
+ else
+ {
+ dps->fc++; /* new file */
+ dps->bc += entry->size;
+ }
+ rb->yield();
+ }
+#ifdef HAVE_DIRCACHE
+ rb->closedir_cached(dir);
+#else
+ rb->closedir(dir);
+#endif
+
+ if(rb->action_userabort(0)) result = false;
+
+ return result;
+}
+
+static bool dir_properties(char* selected_file)
+{
+ DPS dps;
+ char tstr[64];
+ rb->strncpy(dps.dirname, selected_file, MAX_PATH);
+ dps.len = MAX_PATH;
+ dps.dc = 0;
+ dps.fc = 0;
+ dps.bc = 0;
+ if(_dir_properties(&dps))
+ return true;
+
+ rb->snprintf(str_dirname, MAX_PATH, selected_file);
+ rb->snprintf(str_dircount, sizeof str_dircount, "Subdirs: %d", dps.dc);
+ rb->snprintf(str_filecount, sizeof str_filecount, "Files: %d", dps.fc);
+ rb->snprintf(str_size, sizeof str_size, "Size: %s",
+ filesize2string(dps.bc, tstr, sizeof tstr));
+ return true;
+}
+
+char * get_props(int selected_item, void* data, char *buffer)
+{
+ (void)data;
+
+ switch(selected_item)
+ {
+ case 0:
+ rb->strcpy(buffer, str_dirname);
+ break;
+ case 1:
+ rb->strcpy(buffer, its_a_dir ? str_dircount : str_filename);
+ break;
+ case 2:
+ rb->strcpy(buffer, its_a_dir ? str_filecount : str_size);
+ break;
+ case 3:
+ rb->strcpy(buffer, its_a_dir ? str_size : str_date);
+ break;
+ case 4:
+ rb->strcpy(buffer, its_a_dir ? "" : str_time);
+ break;
+ default:
+ rb->strcpy(buffer, "ERROR");
+ break;
+ }
+ return buffer;
+}
+
+enum plugin_status plugin_start(struct plugin_api* api, void* file)
+{
+ rb = api;
+
+ struct gui_synclist properties_lists;
+ int button;
+ bool prev_show_statusbar;
+ bool quit = false;
+
+ /* determine if it's a file or a directory */
+ bool found = false;
+#ifdef HAVE_DIRCACHE
+ DIRCACHED* dir;
+ struct dircache_entry* entry;
+#else
+ DIR* dir;
+ struct dirent* entry;
+#endif
+ char* ptr = rb->strrchr((char*)file, '/') + 1;
+ int dirlen = (ptr - (char*)file);
+ rb->strncpy(str_dirname, (char*)file, dirlen);
+ str_dirname[dirlen] = 0;
+
+#ifdef HAVE_DIRCACHE
+ dir = rb->opendir_cached(str_dirname);
+#else
+ dir = rb->opendir(str_dirname);
+#endif
+ if (dir)
+ {
+#ifdef HAVE_DIRCACHE
+ while(0 != (entry = rb->readdir_cached(dir)))
+#else
+ while(0 != (entry = rb->readdir(dir)))
+#endif
+ {
+ if(!rb->strcmp(entry->d_name, file+dirlen))
+ {
+ its_a_dir = entry->attribute & ATTR_DIRECTORY ? true : false;
+ found = true;
+ break;
+ }
+ }
+#ifdef HAVE_DIRCACHE
+ rb->closedir_cached(dir);
+#else
+ rb->closedir(dir);
+#endif
+ }
+ /* now we know if it's a file or a dir or maybe something failed */
+
+ if(!found)
+ {
+ /* weird: we couldn't find the entry. This Should Never Happen (TM) */
+ rb->lcd_clear_display();
+ rb->lcd_puts(0,0,"File/Dir not found:");
+ rb->lcd_puts(0,1,(char*)file);
+ rb->lcd_update();
+ rb->action_userabort(TIMEOUT_BLOCK);
+ return PLUGIN_OK;
+ }
+
+ /* get the info */
+ if(its_a_dir)
+ {
+ if(!dir_properties((char*)file))
+ return PLUGIN_OK;
+ }
+ else
+ {
+ if(!file_properties((char*)file))
+ return PLUGIN_OK;
+ }
+
+ /* prepare the list for the user */
+ prev_show_statusbar = rb->global_settings->statusbar;
+ rb->global_settings->statusbar = false;
+
+ rb->gui_synclist_init(&properties_lists, &get_props, file, false, 1);
+ rb->gui_synclist_set_title(&properties_lists, its_a_dir ?
+ "Directory properties" :
+ "File properties", NOICON);
+ rb->gui_synclist_set_icon_callback(&properties_lists, NULL);
+ rb->gui_synclist_set_nb_items(&properties_lists, its_a_dir ? 4 : 5);
+ rb->gui_synclist_limit_scroll(&properties_lists, true);
+ rb->gui_synclist_select_item(&properties_lists, 0);
+ rb->gui_synclist_draw(&properties_lists);
+
+ while(!quit)
+ {
+ button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
+ if (rb->gui_synclist_do_button(&properties_lists,button,LIST_WRAP_ON))
+ continue;
+ switch(button)
+ {
+ case ACTION_STD_CANCEL:
+ quit = true;
+ break;
+ default:
+ if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
+ {
+ rb->global_settings->statusbar = prev_show_statusbar;
+ return PLUGIN_USB_CONNECTED;
+ }
+ }
+ }
+ rb->global_settings->statusbar = prev_show_statusbar;
+ rb->action_signalscreenchange();
+
+ return PLUGIN_OK;
+}
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index d9ecd6b..35ad708 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -27,3 +27,4 @@ tap,viewers/zxbox,66 52 4A 66 52 4A
sna,viewers/zxbox,66 52 4A 66 52 4A
tzx,viewers/zxbox,66 52 4A 66 52 4A
z80,viewers/zxbox,66 52 4A 66 52 4A
+zzz,viewers/properties,00 00 00 00 00 00
diff --git a/docs/CREDITS b/docs/CREDITS
index b87ac32..b673e44 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -250,3 +250,4 @@ Travis Hyyppa
Ian Webber
Pavel Gnelitsa
Lutz Böhne
+Will Robertson