From 75b6abb11411f5c27f9aa21329164e6ef16f9972 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sat, 15 Apr 2006 13:57:15 +0000 Subject: [PATCH] Proper chunked browsing support when dirbuffer limit is reached. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9681 a1c6a512-1295-4272-9138-f99709370657 --- apps/tagtree.c | 385 +++++++++++++++++++++++-------------------------- apps/tagtree.h | 12 +- apps/tree.c | 10 +- 3 files changed, 190 insertions(+), 217 deletions(-) diff --git a/apps/tagtree.c b/apps/tagtree.c index 195287862f..ccf926163a 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -45,12 +45,6 @@ static int tagtree_play_folder(struct tree_context* c); static char searchstring[32]; -struct tagentry { - char *name; - int newtable; - int extraseek; -}; - #define MAX_TAGS 5 struct search_instruction { @@ -66,6 +60,9 @@ static struct search_instruction *si, *csi; static int si_count = 0; static const char *strp; +static int current_offset; +static int current_entry_count; + static int get_token_str(char *buf, int size) { /* Find the start. */ @@ -354,16 +351,162 @@ void tagtree_init(void) audiobuf += sizeof(struct search_instruction) * si_count + 4; } +bool show_search_progress(bool init, int count) +{ + static int last_tick = 0; + + if (init) + { + last_tick = current_tick; + return true; + } + + if (current_tick - last_tick > HZ/2) + { + gui_syncsplash(0, true, str(LANG_PLAYLIST_SEARCH_MSG), count, +#if CONFIG_KEYPAD == PLAYER_PAD + str(LANG_STOP_ABORT) +#else + str(LANG_OFF_ABORT) +#endif + ); + if (SETTINGS_CANCEL == button_get(false)) + return false; + last_tick = current_tick; + } + + return true; +} + +int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, + int offset, bool init) +{ + struct tagentry *dptr = (struct tagentry *)c->dircache; + int i; + int namebufused = 0; + int total_count = 0; + int extra = c->currextra; + bool sort = false; + + if (init +#ifdef HAVE_TC_RAMCACHE + && !tagcache_is_ramcache() +#endif + ) + { + show_search_progress(true, 0); + gui_syncsplash(0, true, str(LANG_PLAYLIST_SEARCH_MSG), + 0, csi->name); + } + + tagcache_search(tcs, csi->tagorder[extra]); + for (i = 0; i < extra; i++) + { + tagcache_search_add_filter(tcs, csi->tagorder[i], csi->result_seek[i]); + sort = true; + } + + for (i = 0; i < csi->clause_count[extra]; i++) + { + tagcache_search_add_clause(tcs, &csi->clause[extra][i]); + sort = true; + } + + current_offset = offset; + current_entry_count = 0; + c->dirfull = false; + while (tagcache_get_next(tcs)) + { + if (total_count++ < offset) + continue; + + dptr->newtable = tcs->result_seek; + if (!tcs->ramsearch || csi->tagorder[extra] == tag_title) + { + int tracknum = -1; + + dptr->name = &c->name_buffer[namebufused]; + if (csi->tagorder[extra] == tag_title) + tracknum = tagcache_get_numeric(tcs, tag_tracknumber); + + if (tracknum > 0) + { + snprintf(dptr->name, c->name_buffer_size - namebufused, "%02d. %s", + tracknum, tcs->result); + namebufused += strlen(dptr->name) + 1; + if (namebufused >= c->name_buffer_size) + { + logf("chunk mode #1: %d", current_entry_count); + c->dirfull = true; + sort = false; + break ; + } + } + else + { + namebufused += tcs->result_len; + if (namebufused >= c->name_buffer_size) + { + logf("chunk mode #2: %d", current_entry_count); + c->dirfull = true; + sort = false; + break ; + } + strcpy(dptr->name, tcs->result); + } + } + else + dptr->name = tcs->result; + + dptr++; + current_entry_count++; + + if (current_entry_count >= global_settings.max_files_in_dir) + { + logf("chunk mode #3: %d", current_entry_count); + c->dirfull = true; + sort = false; + break ; + } + + if (init && !tcs->ramsearch) + { + if (!show_search_progress(false, i)) + { + tagcache_search_finish(tcs); + return current_entry_count; + } + } + } + + if (sort) + qsort(c->dircache, current_entry_count, c->dentry_size, compare); + + if (!init) + { + tagcache_search_finish(tcs); + return current_entry_count; + } + + while (tagcache_get_next(tcs)) + { + if (!tcs->ramsearch) + { + if (!show_search_progress(false, total_count)) + break; + } + total_count++; + } + + tagcache_search_finish(tcs); + return total_count; +} + int tagtree_load(struct tree_context* c) { int i; - int namebufused = 0; struct tagentry *dptr = (struct tagentry *)c->dircache; - bool sort = false; - int last_tick; - int table = c->currtable; - int extra = c->currextra; c->dentry_size = sizeof(struct tagentry); @@ -374,9 +517,6 @@ int tagtree_load(struct tree_context* c) c->currtable = table; } - if (c->dirfull) - table = chunked_next; - switch (table) { case root: { for (i = 0; i < si_count; i++) @@ -387,125 +527,24 @@ int tagtree_load(struct tree_context* c) dptr++; } c->dirlength = c->filesindir = i; + current_offset = 0; + current_entry_count = i; return c->dirlength; } case navibrowse: logf("navibrowse..."); -#ifdef HAVE_TC_RAMCACHE - if (!tagcache_is_ramcache()) -#endif - gui_syncsplash(0, true, str(LANG_PLAYLIST_SEARCH_MSG), - 0, csi->name); - - tagcache_search(&tcs, csi->tagorder[extra]); - for (i = 0; i < extra; i++) - { - tagcache_search_add_filter(&tcs, csi->tagorder[i], csi->result_seek[i]); - sort = true; - } - - for (i = 0; i < csi->clause_count[extra]; i++) - { - tagcache_search_add_clause(&tcs, &csi->clause[extra][i]); - sort = true; - } + i = retrieve_entries(c, &tcs, 0, true); break; - case chunked_next: - logf("chunked next..."); - break; - default: logf("Unsupported table %d\n", table); return -1; } - i = 0; - namebufused = 0; - c->dirfull = false; - last_tick = current_tick; - while (tagcache_get_next(&tcs)) - { - dptr->newtable = tcs.result_seek; - if (!tcs.ramsearch || csi->tagorder[extra] == tag_title) - { - int tracknum = -1; - - dptr->name = &c->name_buffer[namebufused]; - if (csi->tagorder[extra] == tag_title) - tracknum = tagcache_get_numeric(&tcs, tag_tracknumber); - - if (tracknum > 0) - { - snprintf(dptr->name, c->name_buffer_size - namebufused, "%02d. %s", - tracknum, tcs.result); - namebufused += strlen(dptr->name) + 1; - if (namebufused >= c->name_buffer_size) - { - logf("buffer full, 1 entry missed."); - c->dirfull = true; - break ; - } - } - else - { - namebufused += tcs.result_len; - if (namebufused >= c->name_buffer_size) - { - logf("buffer full, 1 entry missed."); - c->dirfull = true; - break ; - } - strcpy(dptr->name, tcs.result); - } - } - else - dptr->name = tcs.result; - - dptr++; - i++; - /** - * Estimate when we are running out of space so we can stop - * and enabled chunked browsing without missing entries. - */ - if (i >= global_settings.max_files_in_dir - 1 - || namebufused + 200 > c->name_buffer_size) - { - c->dirfull = true; - break ; - } - - if (!tcs.ramsearch && current_tick - last_tick > HZ/2) - { - gui_syncsplash(0, true, str(LANG_PLAYLIST_SEARCH_MSG), i, -#if CONFIG_KEYPAD == PLAYER_PAD - str(LANG_STOP_ABORT) -#else - str(LANG_OFF_ABORT) -#endif - ); - if (SETTINGS_CANCEL == button_get(false)) - break ; - last_tick = current_tick; - } - } - - if (sort) - qsort(c->dircache, i, c->dentry_size, compare); - - if (c->dirfull) - { - dptr->name = "===>"; - dptr->newtable = chunked_next; - dptr++; - i++; - } - else - tagcache_search_finish(&tcs); - + /* The _total_ numer of entries available. */ c->dirlength = c->filesindir = i; return i; @@ -514,17 +553,10 @@ int tagtree_load(struct tree_context* c) int tagtree_enter(struct tree_context* c) { int rc = 0; - struct tagentry *dptr = (struct tagentry *)c->dircache; + struct tagentry *dptr; int newextra; - dptr += c->selected_item; - - if (dptr->newtable == chunked_next) - { - c->selected_item=0; - gui_synclist_select_item(&tree_lists, c->selected_item); - return 0; - } + dptr = tagtree_get_entry(c, c->selected_item); c->dirfull = false; newextra = dptr->newtable; @@ -618,9 +650,9 @@ void tagtree_exit(struct tree_context* c) int tagtree_get_filename(struct tree_context* c, char *buf, int buflen) { - struct tagentry *entry = (struct tagentry *)c->dircache; + struct tagentry *entry; - entry += c->selected_item; + entry = tagtree_get_entry(c, c->selected_item); tagcache_search(&tcs, tag_filename); tagcache_search_add_filter(&tcs, tag_title, entry->newtable); @@ -636,71 +668,11 @@ int tagtree_get_filename(struct tree_context* c, char *buf, int buflen) return 0; } - -#if 0 -bool tagtree_rename_tag(struct tree_context *c, const char *newtext) -{ - struct tagentry *dptr = (struct tagentry *)c->dircache; - int extra, extra2; - int type; - - dptr += c->selected_item; - extra = dptr->newtable; - extra2 = dptr->extraseek; - - switch (c->currtable) { - case allgenres: - tagcache_search(&tcs, tag_title); - tagcache_search_add_filter(&tcs, tag_genre, extra); - type = tag_genre; - break; - - case allalbums: - tagcache_search(&tcs, tag_title); - tagcache_search_add_filter(&tcs, tag_album, extra); - type = tag_album; - break; - - case allartists: - tagcache_search(&tcs, tag_title); - tagcache_search_add_filter(&tcs, tag_artist, extra); - type = tag_artist; - break; - - case artist4genres: - tagcache_search(&tcs, tag_title); - tagcache_search_add_filter(&tcs, tag_genre, extra); - type = tag_artist; - break; - - case albums4artist: - tagcache_search(&tcs, tag_title); - tagcache_search_add_filter(&tcs, tag_album, extra); - tagcache_search_add_filter(&tcs, tag_artist, extra2); - type = tag_album; - break; - - default: - logf("wrong table"); - return false; - } - - while (tagcache_get_next(&tcs)) - { - // tagcache_modify(&tcs, type, newtext); - } - - tagcache_search_finish(&tcs); - return true; -} -#endif static int tagtree_play_folder(struct tree_context* c) { - struct tagentry *entry = (struct tagentry *)c->dircache; int i; char buf[MAX_PATH]; - int last_tick = 0; if (playlist_create(NULL, NULL) < 0) { @@ -712,21 +684,10 @@ static int tagtree_play_folder(struct tree_context* c) tagcache_search(&tcs, tag_filename); for (i=0; i < c->filesindir; i++) { - if (current_tick - last_tick > HZ/2) - { - gui_syncsplash(0, true, str(LANG_PLAYLIST_SEARCH_MSG), i, -#if CONFIG_KEYPAD == PLAYER_PAD - str(LANG_STOP_ABORT) -#else - str(LANG_OFF_ABORT) -#endif - ); - if (SETTINGS_CANCEL == button_get(false)) - break ; - last_tick = current_tick; - } + if (!show_search_progress(false, i)) + break; - if (!tagcache_retrieve(&tcs, entry[i].newtable, + if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->newtable, buf, sizeof buf)) { continue; @@ -748,11 +709,19 @@ static int tagtree_play_folder(struct tree_context* c) return 0; } -char* tagtree_get_entryname(struct tree_context *c, int id) +struct tagentry* tagtree_get_entry(struct tree_context *c, int id) { - char **buf = c->dircache; - - return buf[id * (c->dentry_size/sizeof(int))]; + struct tagentry *entry = (struct tagentry *)c->dircache; + int realid = id - current_offset; + + /* Load the next chunk if necessary. */ + if (realid >= current_entry_count || realid < 0) + { + retrieve_entries(c, &tcs, MAX(0, id - (current_entry_count / 2)), false); + realid = id - current_offset; + } + + return &entry[realid]; } #ifdef HAVE_LCD_BITMAP diff --git a/apps/tagtree.h b/apps/tagtree.h index 204a028086..f048b0e215 100644 --- a/apps/tagtree.h +++ b/apps/tagtree.h @@ -22,15 +22,19 @@ #include "tagcache.h" #include "tree.h" -enum table { - invalid, root, navibrowse, - chunked_next }; +enum table { invalid, root, navibrowse }; + +struct tagentry { + char *name; + int newtable; + int extraseek; +}; void tagtree_init(void); int tagtree_enter(struct tree_context* c); void tagtree_exit(struct tree_context* c); int tagtree_load(struct tree_context* c); -char* tagtree_get_entryname(struct tree_context *c, int id); +struct tagentry* tagtree_get_entry(struct tree_context *c, int id); #ifdef HAVE_LCD_BITMAP const char* tagtree_get_icon(struct tree_context* c); #else diff --git a/apps/tree.c b/apps/tree.c index 7f63b08ddd..a1068c2da2 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -168,12 +168,12 @@ char * tree_get_filename(int selected_item, void * data, char *buffer) int attr=0; bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; - if (id3db) { - return tagtree_get_entryname(&tc, selected_item); - //char **buf = local_tc->dircache; - //name = buf[selected_item * (local_tc->dentry_size/sizeof(int))]; + if (id3db) + { + return tagtree_get_entry(&tc, selected_item)->name; } - else { + else + { struct entry* dc = local_tc->dircache; struct entry* e = &dc[selected_item]; name = e->name;