database: make parent tables work with plugin
Enables the use of PictureFlow and the Properties plugin with parent tables of ALLSUBENTRIES, such as an album or album artist, instead of individual tracks. Change-Id: I18c4779ed116a48c732ae32b9629e7e0d93ce7c8
This commit is contained in:
parent
4d53d1b52b
commit
32f365bf3c
7 changed files with 214 additions and 85 deletions
|
@ -187,6 +187,9 @@ enum current_activity {
|
|||
ACTIVITY_USBSCREEN
|
||||
};
|
||||
|
||||
/* custom string representation of activity */
|
||||
#define MAKE_ACT_STR(act) ((char[3]){'>', 'A'+ (act), 0x0})
|
||||
|
||||
void beep_play(unsigned int frequency, unsigned int duration,
|
||||
unsigned int amplitude);
|
||||
|
||||
|
|
|
@ -1611,8 +1611,33 @@ static bool list_viewers(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TAGCACHE
|
||||
static bool prepare_database_sel(void *param)
|
||||
{
|
||||
if (context == CONTEXT_ID3DB &&
|
||||
(selected_file_attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO)
|
||||
{
|
||||
if (!strcmp(param, "properties"))
|
||||
strmemccpy(selected_file_path, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER),
|
||||
sizeof(selected_file_path));
|
||||
else if (!tagtree_get_subentry_filename(selected_file_path, MAX_PATH))
|
||||
{
|
||||
onplay_result = ONPLAY_RELOAD_DIR;
|
||||
return false;
|
||||
}
|
||||
|
||||
selected_file = selected_file_path;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool onplay_load_plugin(void *param)
|
||||
{
|
||||
#ifdef HAVE_TAGCACHE
|
||||
if (!prepare_database_sel(param))
|
||||
return false;
|
||||
#endif
|
||||
int ret = filetype_load_plugin((const char*)param, selected_file);
|
||||
if (ret == PLUGIN_USB_CONNECTED)
|
||||
onplay_result = ONPLAY_RELOAD_DIR;
|
||||
|
@ -1717,10 +1742,8 @@ static int clipboard_callback(int action,
|
|||
#ifdef HAVE_TAGCACHE
|
||||
if (context == CONTEXT_ID3DB)
|
||||
{
|
||||
if (((selected_file_attr & FILE_ATTR_MASK) ==
|
||||
FILE_ATTR_AUDIO) &&
|
||||
(this_item == &track_info_item ||
|
||||
this_item == &pictureflow_item))
|
||||
if (this_item == &track_info_item ||
|
||||
this_item == &pictureflow_item)
|
||||
return action;
|
||||
return ACTION_EXIT_MENUITEM;
|
||||
}
|
||||
|
@ -1895,6 +1918,10 @@ static int hotkey_tree_pl_insert_shuffled(void)
|
|||
|
||||
static int hotkey_tree_run_plugin(void *param)
|
||||
{
|
||||
#ifdef HAVE_TAGCACHE
|
||||
if (!prepare_database_sel(param))
|
||||
return ONPLAY_RELOAD_DIR;
|
||||
#endif
|
||||
if (filetype_load_plugin((const char*)param, selected_file) == PLUGIN_GOTO_WPS)
|
||||
return ONPLAY_START_PLAY;
|
||||
|
||||
|
|
|
@ -825,6 +825,9 @@ static const struct plugin_api rockbox_api = {
|
|||
splash_progress_set_delay,
|
||||
fix_path_part,
|
||||
onplay_show_playlist_cat_menu,
|
||||
#if defined(HAVE_TAGCACHE)
|
||||
tagtree_subentries_do_action,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int plugin_buffer_handle;
|
||||
|
|
|
@ -103,6 +103,7 @@ int plugin_open(const char *plugin, const char *parameter);
|
|||
#include "buflib.h"
|
||||
#include "buffering.h"
|
||||
#include "tagcache.h"
|
||||
#include "tagtree.h"
|
||||
#include "viewport.h"
|
||||
#include "ata_idle_notify.h"
|
||||
#include "settings_list.h"
|
||||
|
@ -157,7 +158,7 @@ int plugin_open(const char *plugin, const char *parameter);
|
|||
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
||||
|
||||
/* increase this every time the api struct changes */
|
||||
#define PLUGIN_API_VERSION 263
|
||||
#define PLUGIN_API_VERSION 264
|
||||
|
||||
/* update this to latest version if a change to the api struct breaks
|
||||
backwards compatibility (and please take the opportunity to sort in any
|
||||
|
@ -950,6 +951,9 @@ struct plugin_api {
|
|||
void (*fix_path_part)(char* path, int offset, int count);
|
||||
void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr,
|
||||
void (*add_to_pl_cb));
|
||||
#ifdef HAVE_TAGCACHE
|
||||
bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
|
||||
#endif
|
||||
};
|
||||
|
||||
/* plugin header */
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "lib/id3.h"
|
||||
|
||||
#ifdef HAVE_TAGCACHE
|
||||
#include "lib/mul_id3.h"
|
||||
#endif
|
||||
|
||||
#if !defined(ARRAY_SIZE)
|
||||
#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
|
||||
|
@ -35,12 +40,16 @@ struct dir_stats {
|
|||
enum props_types {
|
||||
PROPS_FILE = 0,
|
||||
PROPS_ID3,
|
||||
PROPS_MUL_ID3,
|
||||
PROPS_DIR
|
||||
};
|
||||
|
||||
static int props_type = PROPS_FILE;
|
||||
|
||||
static struct mp3entry id3;
|
||||
#ifdef HAVE_TAGCACHE
|
||||
static int mul_id3_count;
|
||||
#endif
|
||||
|
||||
static char str_filename[MAX_PATH];
|
||||
static char str_dirname[MAX_PATH];
|
||||
|
@ -118,14 +127,8 @@ static bool file_properties(const char* selected_file)
|
|||
rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
int fd = rb->open(selected_file, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (rb->get_metadata(&id3, fd, selected_file))
|
||||
if (retrieve_id3(&id3, selected_file, false))
|
||||
props_type = PROPS_ID3;
|
||||
|
||||
rb->close(fd);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -369,6 +372,19 @@ static bool determine_file_or_dir(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TAGCACHE
|
||||
bool mul_id3_add(const char *file_name)
|
||||
{
|
||||
if (!retrieve_id3(&id3, file_name, false))
|
||||
return false;
|
||||
|
||||
collect_id3(&id3, mul_id3_count == 0);
|
||||
mul_id3_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum plugin_status plugin_start(const void* parameter)
|
||||
{
|
||||
static struct dir_stats stats =
|
||||
|
@ -380,12 +396,30 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
};
|
||||
|
||||
const char *file = parameter;
|
||||
if(!parameter || (file[0] != '/')) return PLUGIN_ERROR;
|
||||
if(!parameter)
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
#ifdef HAVE_TOUCHSCREEN
|
||||
rb->touchscreen_set_mode(rb->global_settings->touch_mode);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TAGCACHE
|
||||
if (!rb->strcmp(file, MAKE_ACT_STR(ACTIVITY_DATABASEBROWSER))) /* db table selected */
|
||||
{
|
||||
props_type = PROPS_MUL_ID3;
|
||||
init_mul_id3();
|
||||
mul_id3_count = 0;
|
||||
|
||||
if (!rb->tagtree_subentries_do_action(&mul_id3_add) || mul_id3_count == 0)
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
if (mul_id3_count > 1) /* otherwise, the retrieved id3 can be used as-is */
|
||||
write_id3_mul_tracks(&id3);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (file[0] == '/') /* single track selected */
|
||||
{
|
||||
const char* file_name = rb->strrchr(file, '/') + 1;
|
||||
int dirlen = (file_name - file);
|
||||
|
||||
|
@ -408,12 +442,16 @@ enum plugin_status plugin_start(const void* parameter)
|
|||
rb->action_userabort(TIMEOUT_BLOCK);
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
FOR_NB_SCREENS(i)
|
||||
rb->viewportmanager_theme_enable(i, true, NULL);
|
||||
|
||||
bool usb = props_type == PROPS_ID3 ? rb->browse_id3(&id3, 0, 0, &tm) :
|
||||
browse_file_or_dir(&stats);
|
||||
(props_type == PROPS_MUL_ID3 ? rb->browse_id3(&id3, 0, 0, NULL) :
|
||||
browse_file_or_dir(&stats));
|
||||
|
||||
FOR_NB_SCREENS(i)
|
||||
rb->viewportmanager_theme_undo(i, false);
|
||||
|
|
146
apps/tagtree.c
146
apps/tagtree.c
|
@ -2160,6 +2160,27 @@ static bool insert_all_playlist(struct tree_context *c,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool goto_allsubentries(int newtable)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < 2 && (newtable == NAVIBROWSE || newtable == ALLSUBENTRIES))
|
||||
{
|
||||
tagtree_enter(tc, false);
|
||||
tagtree_load(tc);
|
||||
newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
i++;
|
||||
}
|
||||
return (newtable == PLAYTRACK);
|
||||
}
|
||||
|
||||
static void reset_tc_to_prev(int dirlevel, int selected_item)
|
||||
{
|
||||
while (tc->dirlevel > dirlevel)
|
||||
tagtree_exit(tc, false);
|
||||
tc->selected_item = selected_item;
|
||||
tagtree_load(tc);
|
||||
}
|
||||
|
||||
static bool tagtree_insert_selection(int position, bool queue,
|
||||
const char* playlist, bool new_playlist)
|
||||
{
|
||||
|
@ -2167,6 +2188,7 @@ static bool tagtree_insert_selection(int position, bool queue,
|
|||
int dirlevel = tc->dirlevel;
|
||||
int selected_item = tc->selected_item;
|
||||
int newtable;
|
||||
int ret;
|
||||
|
||||
show_search_progress(
|
||||
#ifdef HAVE_DISK_STORAGE
|
||||
|
@ -2176,71 +2198,101 @@ static bool tagtree_insert_selection(int position, bool queue,
|
|||
#endif
|
||||
, 0);
|
||||
|
||||
|
||||
/* We need to set the table to allsubentries. */
|
||||
newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
|
||||
/* Insert a single track? */
|
||||
if (newtable == PLAYTRACK)
|
||||
if (newtable == PLAYTRACK) /* Insert a single track? */
|
||||
{
|
||||
if (tagtree_get_filename(tc, buf, sizeof buf) < 0)
|
||||
{
|
||||
logf("tagtree_get_filename failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
playlist_insert_track(NULL, buf, position, queue, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newtable == NAVIBROWSE)
|
||||
ret = goto_allsubentries(newtable);
|
||||
if (ret)
|
||||
{
|
||||
tagtree_enter(tc, false);
|
||||
tagtree_load(tc);
|
||||
newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
}
|
||||
else if (newtable != ALLSUBENTRIES)
|
||||
{
|
||||
logf("unsupported table: %d", newtable);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now the current table should be allsubentries. */
|
||||
if (newtable != PLAYTRACK)
|
||||
{
|
||||
tagtree_enter(tc, false);
|
||||
tagtree_load(tc);
|
||||
newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
|
||||
/* And now the newtable should be playtrack. */
|
||||
if (newtable != PLAYTRACK)
|
||||
{
|
||||
logf("newtable: %d !!", newtable);
|
||||
while (tc->dirlevel > dirlevel)
|
||||
tagtree_exit(tc, false);
|
||||
tagtree_load(tc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (tc->filesindir <= 0)
|
||||
splash(HZ, ID2P(LANG_END_PLAYLIST));
|
||||
else
|
||||
{
|
||||
logf("insert_all_playlist");
|
||||
if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
|
||||
else if (!insert_all_playlist(tc, playlist, new_playlist, position, queue))
|
||||
splash(HZ*2, ID2P(LANG_FAILED));
|
||||
}
|
||||
|
||||
/* Finally return the dirlevel to its original value. */
|
||||
while (tc->dirlevel > dirlevel)
|
||||
tagtree_exit(tc, false);
|
||||
tc->selected_item = selected_item;
|
||||
tagtree_load(tc);
|
||||
|
||||
return true;
|
||||
reset_tc_to_prev(dirlevel, selected_item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Execute action_cb for all subentries of the current table's
|
||||
* selected item, handing over each entry's filename in the
|
||||
* callback function parameter.
|
||||
*/
|
||||
bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name))
|
||||
{
|
||||
struct tagcache_search tcs;
|
||||
int i, n;
|
||||
unsigned long last_tick;
|
||||
char buf[MAX_PATH];
|
||||
int ret = true;
|
||||
int dirlevel = tc->dirlevel;
|
||||
int selected_item = tc->selected_item;
|
||||
int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
|
||||
cpu_boost(true);
|
||||
if (!goto_allsubentries(newtable))
|
||||
ret = false;
|
||||
else if (tagcache_search(&tcs, tag_filename))
|
||||
{
|
||||
last_tick = current_tick + HZ/2;
|
||||
splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */
|
||||
n = tc->filesindir;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
splash_progress(i, n, "%s (%s)", str(LANG_WAIT), str(LANG_OFF_ABORT));
|
||||
if (TIME_AFTER(current_tick, last_tick + HZ/4))
|
||||
{
|
||||
if (action_userabort(TIMEOUT_NOBLOCK))
|
||||
break;
|
||||
last_tick = current_tick;
|
||||
}
|
||||
|
||||
if (!tagcache_retrieve(&tcs, tagtree_get_entry(tc, i)->extraseek,
|
||||
tcs.type, buf, sizeof buf)
|
||||
|| !action_cb(buf))
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
|
||||
tagcache_search_finish(&tcs);
|
||||
}
|
||||
else
|
||||
{
|
||||
splash(HZ, ID2P(LANG_TAGCACHE_BUSY));
|
||||
ret = false;
|
||||
}
|
||||
reset_tc_to_prev(dirlevel, selected_item);
|
||||
cpu_boost(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try to return first subentry's filename for current selection
|
||||
*/
|
||||
bool tagtree_get_subentry_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
int ret = true;
|
||||
int dirlevel = tc->dirlevel;
|
||||
int selected_item = tc->selected_item;
|
||||
int newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
|
||||
|
||||
if (!goto_allsubentries(newtable) || tagtree_get_filename(tc, buf, bufsize) < 0)
|
||||
ret = false;
|
||||
|
||||
reset_tc_to_prev(dirlevel, selected_item);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool tagtree_current_playlist_insert(int position, bool queue)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,8 @@ char *tagtree_get_title(struct tree_context* c);
|
|||
int tagtree_get_attr(struct tree_context* c);
|
||||
int tagtree_get_icon(struct tree_context* c);
|
||||
int tagtree_get_filename(struct tree_context* c, char *buf, int buflen);
|
||||
bool tagtree_get_subentry_filename(char *buf, size_t bufsize);
|
||||
bool tagtree_subentries_do_action(bool (*action_cb)(const char *file_name));
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue