Index: apps/tagtree.h =================================================================== --- apps/tagtree.h (revision 27667) +++ apps/tagtree.h (working copy) @@ -28,12 +28,13 @@ #define TAGNAVI_VERSION "#! rockbox/tagbrowser/2.0" #define TAGMENU_MAX_ITEMS 64 #define TAGMENU_MAX_MENUS 32 -#define TAGMENU_MAX_FMTS 32 +#define TAGMENU_MAX_FMTS 48 struct tagentry { char *name; int newtable; int extraseek; + int strip; }; bool tagtree_export(void); Index: apps/tagcache.c =================================================================== --- apps/tagcache.c (revision 27667) +++ apps/tagcache.c (working copy) @@ -961,7 +961,8 @@ } } - if (!check_against_clause(seek, str, clause[i])) + /* Handle case where str is empty - pass in "" to allow filters to work */ + if (!check_against_clause(seek, ((str[0] == '\0') ? UNTAGGED : str), clause[i])) return false; } } @@ -990,13 +991,10 @@ } read(fd, str, tfe.tag_length); - - /* Check if entry has been deleted. */ - if (str[0] == '\0') - break; } - if (!check_against_clause(seek, str, clause[i])) + /* Handle case where str is empty - pass in "" to allow filters to work */ + if (!check_against_clause(seek, ((str[0] == '\0') ? UNTAGGED : str), clause[i])) return false; } } @@ -1308,25 +1306,9 @@ } bool tagcache_search_add_clause(struct tagcache_search *tcs, - struct tagcache_search_clause *clause) + struct tagcache_search_clause *clause, + bool addfullclause) { - int i; - - if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES) - { - logf("Too many clauses"); - return false; - } - - /* Check if there is already a similar filter in present (filters are - * much faster than clauses). - */ - for (i = 0; i < tcs->filter_count; i++) - { - if (tcs->filter_tag[i] == clause->tag) - return true; - } - if (!TAGCACHE_IS_NUMERIC(clause->tag) && tcs->idxfd[clause->tag] < 0) { char buf[MAX_PATH], path[MAX_PATH]; @@ -1335,10 +1317,20 @@ file = get_user_file_path(buf, IS_FILE | NEED_WRITE, path, sizeof(path)); tcs->idxfd[clause->tag] = open(file, O_RDONLY); } + + /* Only add the full clause if required */ + if (addfullclause) + { + if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES) + { + logf("Too many clauses"); + return false; + } + + tcs->clause[tcs->clause_count] = clause; + tcs->clause_count++; + } - tcs->clause[tcs->clause_count] = clause; - tcs->clause_count++; - return true; } Index: apps/tagcache.h =================================================================== --- apps/tagcache.h (revision 27667) +++ apps/tagcache.h (working copy) @@ -50,7 +50,7 @@ #define IDX_BUF_DEPTH 64 /* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */ -#define TAGCACHE_MAGIC 0x5443480d +#define TAGCACHE_MAGIC 0x5443481d /* How much to allocate extra space for ramcache. */ #define TAGCACHE_RESERVE 32768 @@ -75,7 +75,7 @@ /* Idle time before committing events in the command queue. */ #define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2 -#define TAGCACHE_MAX_FILTERS 4 +#define TAGCACHE_MAX_FILTERS 5 #define TAGCACHE_MAX_CLAUSES 32 /* Tag database files. */ @@ -215,7 +215,8 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs, int tag, int seek); bool tagcache_search_add_clause(struct tagcache_search *tcs, - struct tagcache_search_clause *clause); + struct tagcache_search_clause *clause, + bool addfullclause); bool tagcache_get_next(struct tagcache_search *tcs); bool tagcache_retrieve(struct tagcache_search *tcs, int idxid, int tag, char *buf, long size); Index: apps/tagtree.c =================================================================== --- apps/tagtree.c (revision 27667) +++ apps/tagtree.c (working copy) @@ -91,11 +91,21 @@ menu_load, }; +/* String presentation of the tags defined in tagcache.h. Must be in correct order! */ +static const char *tags_str[] = { "artist", "album", "genre", "title", + "filename", "composer", "comment", "albumartist", "grouping", "year", + "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", + "playtime", "lastplayed", "commitid", "mtime" }; + +/* String presentation of the clauses defined in tagcache.h. Must be in correct order! */ +/* static const char *clause_str[] = { "NONE", "=", "!=", ">", ">=", + "<", "<=", "~", "!~", "^", "!^", "$", "!$", "@" }; */ + /* Capacity 10 000 entries (for example 10k different artists) */ #define UNIQBUF_SIZE (64*1024) static long *uniqbuf; -#define MAX_TAGS 5 +#define MAX_TAGS 6 #define MAX_MENU_ID_SIZE 32 static bool sort_inverse; @@ -1052,7 +1062,7 @@ struct tagcache_search tcs; struct tagentry *dptr = (struct tagentry *)c->dircache; struct display_format *fmt; - int i; + int i, j; int namebufused = 0; int total_count = 0; int special_entry_count = 0; @@ -1060,7 +1070,9 @@ int tag; bool sort = false; int sort_limit; - int strip; + bool strip = false; + bool alltracks = false; + char all_tracks_fmt[MAX_PATH]; /* Show search progress straight away if the disk needs to spin up, otherwise show it after the normal 1/2 second delay */ @@ -1074,6 +1086,8 @@ if (c->currtable == ALLSUBENTRIES) { + alltracks = true; /* cache flag defining whether this is the AllTracks menu */ + sort = true; /* default the all subentries to always sort */ tag = tag_title; level--; } @@ -1089,6 +1103,7 @@ if (level || csi->clause_count[0] || TAGCACHE_IS_NUMERIC(tag)) sort = true; + /* Add filters for each parent level */ for (i = 0; i < level; i++) { if (TAGCACHE_IS_NUMERIC(csi->tagorder[i])) @@ -1100,7 +1115,7 @@ cc.type = clause_is; cc.numeric = true; cc.numeric_data = csi->result_seek[i]; - tagcache_search_add_clause(&tcs, &cc); + tagcache_search_add_clause(&tcs, &cc, true); } else { @@ -1108,62 +1123,108 @@ csi->result_seek[i]); } } - + + /* Add clauses for each level in the menu */ for (i = 0; i <= level; i++) { int j; for (j = 0; j < csi->clause_count[i]; j++) - tagcache_search_add_clause(&tcs, csi->clause[i][j]); + tagcache_search_add_clause(&tcs, csi->clause[i][j], true); } current_offset = offset; current_entry_count = 0; c->dirfull = false; - fmt = NULL; - for (i = 0; i < format_count; i++) + if (alltracks) { - if (formats[i]->group_id == csi->format_id[level]) - fmt = formats[i]; + /* All Tracks format functionality */ + sort = true; + all_tracks_fmt[0] = '\0'; + + /* Construct the All format name by concatenating the menu level tags */ + for (i = 0; i <= level; i++) + { + strcat(all_tracks_fmt, tags_str[csi->tagorder[i]]); + strcat(all_tracks_fmt, "."); + } + strcat(all_tracks_fmt, "All"); + + /* look for any AllTracks format matching the derived format name */ + fmt = NULL; + for (i = 0; i < format_count; i++) + { + if (!strcasecmp(formats[i]->name, all_tracks_fmt)) + { + /* add all possible clauses for all formats */ + fmt = formats[i]; + for (j = 0; j < fmt->clause_count; j++) + { + tagcache_search_add_clause(&tcs, fmt->clause[j], false); + } + } + } } + else + { + fmt = NULL; + for (i = 0; i < format_count; i++) + { + if (formats[i]->group_id == csi->format_id[level]) + { + /* Ensure that tags from all clauses for the fmt are loaded */ + fmt = formats[i]; + for (j = 0; j < fmt->clause_count; j++) + { + tagcache_search_add_clause(&tcs, fmt->clause[j], false); + } + } + } + } + /* The assigning of the sort_inverse and sort_limit fields here is a bit arbitrary since any + track title can match any one of the associated formats, each of which can have a different + set of values for the sort inverse and sort limit attributes. */ if (fmt) { sort_inverse = fmt->sort_inverse; sort_limit = fmt->limit; - strip = fmt->strip; sort = true; } else { + /* No global format */ sort_inverse = false; sort_limit = 0; - strip = 0; } - if (tag != tag_title && tag != tag_filename) + if ((tag != tag_title) && (tag != tag_filename)) { if (offset == 0) { + /* Adds the option */ dptr->newtable = ALLSUBENTRIES; dptr->name = str(LANG_TAGNAVI_ALL_TRACKS); dptr++; current_entry_count++; + special_entry_count++; } if (offset <= 1) { + /* Adds the option */ dptr->newtable = NAVIBROWSE; dptr->name = str(LANG_TAGNAVI_RANDOM); dptr->extraseek = -1; dptr++; current_entry_count++; + special_entry_count++; } - special_entry_count+=2; } total_count += special_entry_count; + /* Now cycle through each entry and apply any formatting */ while (tagcache_get_next(&tcs)) { if (total_count++ < offset) @@ -1175,20 +1236,25 @@ str(LANG_TAGNAVI_UNTAGGED), TAG_MAXLEN )+1; } - dptr->newtable = NAVIBROWSE; - if (tag == tag_title || tag == tag_filename) + dptr->strip = 0; /* set the default strip amount for this entry */ + if ((tag == tag_title) || (tag == tag_filename)) { dptr->newtable = PLAYTRACK; dptr->extraseek = tcs.idx_id; } else + { + dptr->newtable = NAVIBROWSE; dptr->extraseek = tcs.result_seek; + } fmt = NULL; /* Check the format */ for (i = 0; i < format_count; i++) { - if (formats[i]->group_id != csi->format_id[level]) + /* Handle the allsubentries case as well - look for format defined in all_tracks_fmt */ + if (((formats[i]->group_id != csi->format_id[level]) && !alltracks) || + (alltracks && strcasecmp(formats[i]->name, all_tracks_fmt))) continue; if (tagcache_check_clauses(&tcs, formats[i]->clause, @@ -1211,6 +1277,11 @@ tagcache_search_finish(&tcs); return 0; } + + /* Set the strip amount for this track if the title was successfully formatted */ + dptr->strip = fmt->strip; + if (!strip && (fmt->strip > 0)) + strip = true; /* cached strip flag */ } dptr->name = &c->name_buffer[namebufused]; @@ -1290,15 +1361,23 @@ if (strip) { + /* Now perform strip based on the format applied to each track name */ dptr = c->dircache; for (i = 0; i < total_count; i++, dptr++) { - int len = strlen(dptr->name); - - if (len < strip) - continue; - - dptr->name = &dptr->name[strip]; + /* Skip the special entries in the list */ + if (i < special_entry_count) + continue; + + if (dptr->strip > 0) + { + int len = strlen(dptr->name); + + if (len < dptr->strip) + continue; + + dptr->name = &dptr->name[dptr->strip]; + } } }