summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2006-11-30 22:29:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2006-11-30 22:29:48 +0000
commit0f02e4f7a0a202a9efb26833f156a72a3541b2f8 (patch)
treef376a667ce28f96451c4cdf4e86d650192aeecfe /apps
parentcd605cffa35cff0c59026e5796aa9488ce590aea (diff)
downloadrockbox-0f02e4f7a0a202a9efb26833f156a72a3541b2f8.zip
rockbox-0f02e4f7a0a202a9efb26833f156a72a3541b2f8.tar.gz
rockbox-0f02e4f7a0a202a9efb26833f156a72a3541b2f8.tar.bz2
rockbox-0f02e4f7a0a202a9efb26833f156a72a3541b2f8.tar.xz
File and (recursive) directories properties in the file browser context menu. Uses dircache if possible (plugin api expanded). Is actually implemented as plugin. Small parts taken from earlier work by Will Robertson.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11630 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-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
8 files changed, 409 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