view mde/content/ContentLoader.d @ 170:e45226d3deae

Context menu services not applicable to the current type can now be hidden. Added files missing from previous commits.
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 29 Jun 2009 21:20:16 +0200
parents 42fb97d9ff9e
children
line wrap: on
line source

/* LICENSE BLOCK
Part of mde: a Modular D game-oriented Engine
Copyright © 2007-2008 Diggory Hardy

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

/******************************************************************************
 * ContentLoader handles saving and loading of all Content values, as
 * well as translation (loading Contents' name and desc strings from file).
 * 
 * In other words, the values of Content classes automatically persist across
 * runs (provided save() and load() are called appropriately).
 * If content is created before calling load() its value is set by load(); if
 * it is created after, its value is set during its creation.
 *****************************************************************************/
module mde.content.ContentLoader;

import mde.content.AStringContent;
import mde.content.ValueCache;
import mde.file.paths;	// PRIORITY enum
import mde.content.Translation;

import tango.util.log.Log : Log, Logger;
private Logger logger;
static this () {
    logger = Log.getLogger ("mde.gui.content.ContentLoader");
}

/// Namespace for the module's functionality
struct ContentLoader {
    private static {	// Templates
        template ContentN(T) {
            static if (is(T == bool)) {
                const char[] ContentN = "BoolContent";
            } else static if (is(T == int)) {
                const char[] ContentN = "IntContent";
            } else static if (is(T == double)) {
                const char[] ContentN = "DoubleContent";
            } else static if (is(T == char[])) {
                const char[] ContentN = "StringContent";
            } else static if (is(T == enumVal)) {
                const char[] ContentN = "EnumContent";
            } else
                static assert (false, "No Content of type "~T.stringof);
        }
        
        // For setting existing content; mixed in in Content.load().
        template setContentMixin(A...) {
            static if (A.length)
                const char[] setContentMixin =
                `foreach (id,val; `~ValueCache.TName!(A[0])~`Data) {
                    auto contP = id in Content.allContent;
                    if (contP) {
                        `~ContentN!(A[0])~` cont = cast(`~ContentN!(A[0])~`) *contP;
                        if (cont)
                            cont.assignNoCng (val);
                    }
                } ` ~ setContentMixin!(A[1..$]);
            else
                const char[] setContentMixin = ``;
        }
    }
static:
    /** Loads all stored content, to an existing Content or a buffer where new
     * content can look up its value.
     * 
     * This would normally include all options, except perhaps key bindings.
     * 
     * Should only be called once. */
    void load () {
    	Content.loaded.loadData (PRIORITY.HIGH_LOW);
        // Add locally-stored options into changes so they don't get lost when writing
        Content.changed.loadData (PRIORITY.HIGH_ONLY);
        with (Content.loaded) {
            mixin (setContentMixin!(ValueCache.TYPES));
        }
    }
    
    /** Saves all changed content.
     *
     * May be called multiple times. */
    void save () {
        Content.changed.saveData;
    }
    
private:
    /* Load translations for all content.
     * Hooked as a change callback for l10n. */
    void translate (IContent) {
        logger.info ("loading translations...");
        Translation trl = Translation.get (l10n());
        
	// Translate existing content:
        foreach (symb, cont; Content.allContent) {
            auto p = symb in trl.entries;
            if (p)
            	cont.name (*p);
        }
        
        // Allow translation of new content:
        Content.translations = trl.entries;
        logger.info ("loaded translations");
    }
    
    StringContent l10n;
    static this () {
        l10n = new StringContent ("MiscOptions.l10n");
        l10n.addCallback (&translate);
    }
}