static SetupFileHash *artworkinfo_cache_new = NULL;
static SetupFileHash *optional_tokens_hash = NULL;
static boolean use_artworkinfo_cache = TRUE;
+static boolean update_artworkinfo_cache = FALSE;
// ----------------------------------------------------------------------------
return TRUE;
}
+static int compareSetupFileData(const void *object1, const void *object2)
+{
+ const struct ConfigInfo *entry1 = (struct ConfigInfo *)object1;
+ const struct ConfigInfo *entry2 = (struct ConfigInfo *)object2;
+
+ return strcmp(entry1->token, entry2->token);
+}
+
static void saveSetupFileHash(SetupFileHash *hash, char *filename)
{
+ int item_count = hashtable_count(hash);
+ int item_size = sizeof(struct ConfigInfo);
+ struct ConfigInfo *sort_array = checked_malloc(item_count * item_size);
FILE *file;
+ int i = 0;
- if (!(file = fopen(filename, MODE_WRITE)))
+ // copy string pointers from hash to array
+ BEGIN_HASH_ITERATION(hash, itr)
{
- Warn("cannot write configuration file '%s'", filename);
+ sort_array[i].token = HASH_ITERATION_TOKEN(itr);
+ sort_array[i].value = HASH_ITERATION_VALUE(itr);
- return;
+ i++;
+
+ if (i > item_count) // should never happen
+ break;
}
+ END_HASH_ITERATION(hash, itr)
- BEGIN_HASH_ITERATION(hash, itr)
+ // sort string pointers from hash in array
+ qsort(sort_array, item_count, item_size, compareSetupFileData);
+
+ if (!(file = fopen(filename, MODE_WRITE)))
{
- fprintf(file, "%s\n", getFormattedSetupEntry(HASH_ITERATION_TOKEN(itr),
- HASH_ITERATION_VALUE(itr)));
+ Warn("cannot write configuration file '%s'", filename);
+
+ return;
}
- END_HASH_ITERATION(hash, itr)
+ for (i = 0; i < item_count; i++)
+ fprintf(file, "%s\n", getFormattedSetupEntry(sort_array[i].token,
+ sort_array[i].value));
fclose(file);
+
+ checked_free(sort_array);
}
SetupFileList *loadSetupFileList(char *filename)
if (entry1->parent_link || entry2->parent_link)
compare_result = (entry1->parent_link ? -1 : +1);
+ else if (entry1->level_group != entry2->level_group)
+ compare_result = (entry1->level_group ? -1 : +1);
else if (entry1->sort_priority == entry2->sort_priority)
- {
- char *name1 = getStringToLower(entry1->name_sorting);
- char *name2 = getStringToLower(entry2->name_sorting);
-
- compare_result = strcmp(name1, name2);
-
- free(name1);
- free(name2);
- }
+ compare_result = strcasecmp(entry1->name_sorting, entry2->name_sorting);
else if (class_sorting1 == class_sorting2)
compare_result = entry1->sort_priority - entry2->sort_priority;
else
ti_new->parent_link = TRUE;
setString(&ti_new->identifier, node_parent->identifier);
- setString(&ti_new->name, ".. (parent directory)");
+ setString(&ti_new->name, BACKLINK_TEXT_PARENT);
setString(&ti_new->name_sorting, ti_new->name);
setString(&ti_new->subdir, STRING_PARENT_DIRECTORY);
static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first)
{
- TreeInfo *ti_new, *ti_new2;
-
if (node_first == NULL)
return NULL;
- ti_new = newTreeInfo();
- setTreeInfoToDefaults(ti_new, TREE_TYPE_LEVEL_DIR);
+ TreeInfo *ti_new = newTreeInfo();
+ int type = node_first->type;
+
+ setTreeInfoToDefaults(ti_new, type);
ti_new->node_parent = NULL;
ti_new->parent_link = FALSE;
setString(&ti_new->identifier, node_first->identifier);
- setString(&ti_new->name, INFOTEXT_LEVEL_DIR);
+ setString(&ti_new->name, TREE_INFOTEXT(type));
setString(&ti_new->name_sorting, ti_new->name);
setString(&ti_new->subdir, STRING_TOP_DIRECTORY);
ti_new->sort_priority = node_first->sort_priority;;
ti_new->latest_engine = node_first->latest_engine;
- setString(&ti_new->class_desc, INFOTEXT_LEVEL_DIR);
+ setString(&ti_new->class_desc, TREE_INFOTEXT(type));
ti_new->node_group = node_first;
ti_new->level_group = TRUE;
- ti_new2 = createParentTreeInfoNode(ti_new);
+ TreeInfo *ti_new2 = createParentTreeInfoNode(ti_new);
- setString(&ti_new2->name, ".. (main menu)");
+ setString(&ti_new2->name, TREE_BACKLINK_TEXT(type));
setString(&ti_new2->name_sorting, ti_new2->name);
return ti_new;
}
+static void setTreeInfoParentNodes(TreeInfo *node, TreeInfo *node_parent)
+{
+ while (node)
+ {
+ if (node->node_group)
+ setTreeInfoParentNodes(node->node_group, node);
+
+ node->node_parent = node_parent;
+
+ node = node->next;
+ }
+}
+
// ----------------------------------------------------------------------------
// functions for handling level and custom artwork info cache
if (artworkinfo_cache_new == NULL)
artworkinfo_cache_new = newSetupFileHash();
+
+ update_artworkinfo_cache = FALSE;
}
static void SaveArtworkInfoCache(void)
{
+ if (!update_artworkinfo_cache)
+ return;
+
char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE);
InitCacheDirectory();
if (timestamp_string == NULL)
return TRUE;
+ if (!fileExists(filename)) // file does not exist
+ return (atoi(timestamp_string) != 0);
+
if (stat(filename, &file_status) != 0) // cannot stat file
return TRUE;
#endif
}
+static void MoveArtworkInfoIntoSubTree(ArtworkDirTree **artwork_node)
+{
+ ArtworkDirTree *artwork_new = newTreeInfo();
+ char *top_node_name = "standalone artwork";
+
+ setTreeInfoToDefaults(artwork_new, (*artwork_node)->type);
+
+ artwork_new->level_group = TRUE;
+
+ setString(&artwork_new->identifier, top_node_name);
+ setString(&artwork_new->name, top_node_name);
+ setString(&artwork_new->name_sorting, top_node_name);
+
+ // create node to link back to current custom artwork directory
+ createParentTreeInfoNode(artwork_new);
+
+ // move existing custom artwork tree into newly created sub-tree
+ artwork_new->node_group->next = *artwork_node;
+
+ // change custom artwork tree to contain only newly created node
+ *artwork_node = artwork_new;
+}
+
static void LoadArtworkInfoFromLevelInfoExt(ArtworkDirTree **artwork_node,
ArtworkDirTree *node_parent,
- LevelDirTree *level_node)
+ LevelDirTree *level_node,
+ boolean empty_level_set_mode)
{
int type = (*artwork_node)->type;
while (level_node)
{
+ boolean empty_level_set = (level_node->levels == 0);
+
// check all tree entries for artwork, but skip parent link entries
- if (!level_node->parent_link)
+ if (!level_node->parent_link && empty_level_set == empty_level_set_mode)
{
TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type);
boolean cached = (artwork_new != NULL);
artwork_new->sort_priority = level_node->sort_priority;
artwork_new->color = LEVELCOLOR(artwork_new);
+
+ update_artworkinfo_cache = TRUE;
}
free(path);
artwork_new->level_group = TRUE;
setString(&artwork_new->identifier, level_node->subdir);
- setString(&artwork_new->name, level_node->name);
- setString(&artwork_new->name_sorting, level_node->name_sorting);
+
+ if (node_parent == NULL) // check for top tree node
+ {
+ char *top_node_name = (empty_level_set_mode ?
+ "artwork for certain level sets" :
+ "artwork included in level sets");
+
+ setString(&artwork_new->name, top_node_name);
+ setString(&artwork_new->name_sorting, top_node_name);
+ }
+ else
+ {
+ setString(&artwork_new->name, level_node->name);
+ setString(&artwork_new->name_sorting, level_node->name_sorting);
+ }
pushTreeInfo(artwork_node, artwork_new);
// recursively step into sub-directory and look for more custom artwork
LoadArtworkInfoFromLevelInfoExt(&artwork_new->node_group, artwork_new,
- level_node->node_group);
+ level_node->node_group,
+ empty_level_set_mode);
// if sub-tree has no custom artwork at all, remove it
if (artwork_new->node_group->next == NULL)
static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node)
{
- LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all);
+ // move peviously loaded artwork tree into separate sub-tree
+ MoveArtworkInfoIntoSubTree(artwork_node);
+
+ // load artwork from level sets into separate sub-trees
+ LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, TRUE);
+ LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, FALSE);
+
+ // add top tree node over all three separate sub-trees
+ *artwork_node = createTopTreeInfoNode(*artwork_node);
+
+ // set all parent links (back links) in complete artwork tree
+ setTreeInfoParentNodes(*artwork_node, NULL);
}
void LoadLevelArtworkInfo(void)