All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.czyzby.lml.util.LmlParserBuilder Maven / Gradle / Ivy

package com.github.czyzby.lml.util;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TooltipManager;
import com.badlogic.gdx.utils.I18NBundle;
import com.github.czyzby.kiwi.util.gdx.reflection.Reflection;
import com.github.czyzby.lml.annotation.processor.OnChangeProcessor;
import com.github.czyzby.lml.parser.LmlData;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.LmlSyntax;
import com.github.czyzby.lml.parser.LmlTemplateReader;
import com.github.czyzby.lml.parser.action.ActionContainer;
import com.github.czyzby.lml.parser.action.ActorConsumer;
import com.github.czyzby.lml.parser.impl.AbstractLmlParser;
import com.github.czyzby.lml.parser.impl.DefaultLmlData;
import com.github.czyzby.lml.parser.impl.DefaultLmlParser;
import com.github.czyzby.lml.parser.tag.LmlAttribute;
import com.github.czyzby.lml.parser.tag.LmlTag;
import com.github.czyzby.lml.parser.tag.LmlTagProvider;

/** Simplifies construction of {@code LmlParser} by initiating an instance of {@link DefaultLmlParser}. Note that
 * {@link LmlParserBuilder#build()} method returns an instance of parser that is actually created in builder's
 * constructor - calling building method multiple times always returns the same parser instance. In a sense, this
 * builder is more of a "preference setter" rather than "complex object constructor".
 *
 * @author MJ */
public class LmlParserBuilder {
    private final AbstractLmlParser parser;

    /** Constructs a new builder that wraps around an instance of {@link DefaultLmlParser}. */
    public LmlParserBuilder() {
        this(new DefaultLmlData());
    }

    /** Constructs a new builder that wraps around an instance of {@link DefaultLmlParser}.
     *
     * @param lmlData stores data needed to properly parse LML templates. */
    public LmlParserBuilder(final LmlData lmlData) {
        parser = getInstanceOfParser(lmlData);
    }

    /** @param lmlData contains LML parsing data.
     * @return a new instance of an extension of {@link AbstractLmlParser}. */
    protected AbstractLmlParser getInstanceOfParser(final LmlData lmlData) {
        return new DefaultLmlParser(lmlData);
    }

    /** @param defaultSkin will be set as the default {@link Skin} instance used when no ID is specified.
     * @return this for chaining. */
    public LmlParserBuilder skin(final Skin defaultSkin) {
        parser.getData().setDefaultSkin(defaultSkin);
        return this;
    }

    /** @param id will register value under this ID (ignoring case).
     * @param skin will be available in LML templates through the chosen ID.
     * @return this for chaining. */
    public LmlParserBuilder skin(final String id, final Skin skin) {
        parser.getData().addSkin(id, skin);
        return this;
    }

    /** @param tag all tags with this name (case ignored) will have the attribute applied.
     * @param attribute name of the attribute.
     * @param defaultValue default value of the attribute, used if attribute is not already set in the tag.
     * @return this for chaining. */
    public LmlParserBuilder style(final String tag, final String attribute, final String defaultValue) {
        parser.getStyleSheet().addStyle(tag, attribute, defaultValue);
        return this;
    }

    /** @param styleSheetPath LML style sheet data file.
     * @return this for chaining. */
    public LmlParserBuilder styles(final FileHandle styleSheetPath) {
        parser.parseStyleSheet(styleSheetPath);
        return this;
    }

    /** @param styleSheetPath path to internal file storing LML style sheet data.
     * @return this for chaining. */
    public LmlParserBuilder stylesPath(final String styleSheetPath) {
        parser.parseStyleSheet(Gdx.files.internal(styleSheetPath));
        return this;
    }

    /** @param defaultPreferences will be set as the default {@link Preferences} instance used when no ID is specified.
     * @return this for chaining. */
    public LmlParserBuilder preferences(final Preferences defaultPreferences) {
        parser.getData().setDefaultPreferences(defaultPreferences);
        return this;
    }

    /** @param id will register value under this ID (ignoring case).
     * @param preferences will be available in LML templates through the chosen ID.
     * @return this for chaining. */
    public LmlParserBuilder preferences(final String id, final Preferences preferences) {
        parser.getData().addPreferences(id, preferences);
        return this;
    }

    /** @param defaultI18nBundle will be set as the default {@link I18NBundle} instance used when no ID is specified.
     * @return this for chaining. */
    public LmlParserBuilder i18nBundle(final I18NBundle defaultI18nBundle) {
        parser.getData().setDefaultI18nBundle(defaultI18nBundle);
        return this;
    }

    /** @param id will register value under this ID (ignoring case).
     * @param i18nBundle will be available in LML templates through the chosen ID.
     * @return this for chaining. */
    public LmlParserBuilder i18nBundle(final String id, final I18NBundle i18nBundle) {
        parser.getData().addI18nBundle(id, i18nBundle);
        return this;
    }

    /** @param defaultTooltipManager will be set as the default {@link TooltipManager} instance used when no ID is
     *            specified.
     * @return this for chaining. */
    public LmlParserBuilder tooltipManager(final TooltipManager defaultTooltipManager) {
        parser.getData().setDefaultTooltipManager(defaultTooltipManager);
        return this;
    }

    /** @param id will register value under this ID (ignoring case).
     * @param tooltipManager will be available in LML templates through the chosen ID.
     * @return this for chaining. */
    public LmlParserBuilder tooltipManager(final String id, final TooltipManager tooltipManager) {
        parser.getData().addTooltipManager(id, tooltipManager);
        return this;
    }

    /** @param id name of the argument, as it will be available in LML templates.
     * @param argument will be converted to string according to its type. Object arrays and iterables are automatically
     *            converted to LML arrays.
     * @return this for chaining.
     * @see LmlUtilities#toAction(String)
     * @see LmlUtilities#toAction(String, String)
     * @see LmlUtilities#toArrayArgument(Iterable)
     * @see LmlUtilities#toArrayArgument(Object...)
     * @see LmlUtilities#toBundleLine(String)
     * @see LmlUtilities#toBundleLine(String, String)
     * @see LmlUtilities#toPreference(String)
     * @see LmlUtilities#toPreference(String, String)
     * @see LmlUtilities#toRangeArrayArgument(Object, int, int) */
    public LmlParserBuilder argument(final String id, final Object argument) {
        parser.getData().addArgument(id, argument);
        return this;
    }

    /** @param id ID of the action as available in LML views. If the passed ID collides with a name of registered
     *            {@link ActionContainer} method, {@link ActorConsumer} takes priority.
     * @param action can consume one argument (usually an actor or a string) and return a value. If a method with the
     *            specified ID appears in a LML template, this action will be found and invoked (or attached as a
     *            listener, or used otherwise). {@link ActorConsumer} does not rely on reflection, so might be somewhat
     *            noticeably faster on some devices, but usually the overhead is very small as opposed to using
     *            reflection-based actions.
     * @return this for chaining.
     * @see #actions(String, ActionContainer) */
    public LmlParserBuilder action(final String id, final ActorConsumer action) {
        parser.getData().addActorConsumer(id, action);
        return this;
    }

    /** @param id ID of the action container, that can be optionally added to method invocations in LML templates. ID
     *            has to be present only if there are method name collisions, otherwise undetermined method will be
     *            chosen.
     * @param actionContainer its one-arg and no-arg methods will be available as actions in LML templates. This uses
     *            reflection, so action containers should be properly included in GWT reflection pool.
     * @return this for chaining.
     * @see com.github.czyzby.lml.annotation.LmlAction */
    public LmlParserBuilder actions(final String id, final ActionContainer actionContainer) {
        parser.getData().addActionContainer(id, actionContainer);
        return this;
    }

    /** @param id ID of the action container, that can be optionally added to method invocations in LML templates. ID
     *            has to be present only if there are method name collisions, otherwise undetermined method will be
     *            chosen.
     * @param actionContainerClass initiated with no-arg constructor using reflection. Its one-arg and no-arg methods
     *            will be available as actions in LML templates. This uses reflection, so action containers should be
     *            properly included in GWT reflection pool.
     * @return this for chaining.
     * @see com.github.czyzby.lml.annotation.LmlAction */
    public LmlParserBuilder actions(final String id, final Class actionContainerClass) {
        return actions(id, Reflection.newInstance(actionContainerClass));
    }

    /** @param processor can process attributes of specified actor base class. Every object of handled class (or class
     *            that extends it) will be able to parse the attribute using this processor.
     * @param names aliases of the attribute, as available in LML templates.
     * @return this for chaining.
     * @see LmlAttribute
     * @see com.github.czyzby.lml.parser.impl.tag.macro.NewAttributeLmlMacroTag */
    public LmlParserBuilder attribute(final LmlAttribute processor, final String... names) {
        parser.getSyntax().addAttributeProcessor(processor, names);
        return this;
    }

    /** @param tagProvider creates instances of {@link LmlTag}. {@link LmlTagProvider} is basically a simple functional
     *            interface - it's the LmlTag implementation that manages the actor. The constructed LmlTag instances
     *            usually handle a single actor at a time.
     * @param names aliases of the tag, as available in LML templates.
     * @return this for chaining.
     * @see LmlTag
     * @see com.github.czyzby.lml.parser.impl.tag.AbstractActorLmlTag
     * @see com.github.czyzby.lml.parser.impl.tag.macro.NewTagLmlMacroTag */
    public LmlParserBuilder tag(final LmlTagProvider tagProvider, final String... names) {
        parser.getSyntax().addTagProvider(tagProvider, names);
        return this;
    }

    /** @param macroTagProvider creates instances of {@link LmlTag}. {@link LmlTagProvider} is basically a simple
     *            functional interface - it's the LmlTag implementation that manages the macro. Macro tags manage text
     *            between their tags, allowing to modify template's structure.
     * @param names aliases of the macro, as available in LML templates.
     * @return this for chaining.
     * @see LmlTag
     * @see com.github.czyzby.lml.parser.impl.tag.AbstractMacroLmlTag
     * @see com.github.czyzby.lml.parser.impl.tag.macro.MetaLmlMacroTag */
    public LmlParserBuilder macro(final LmlTagProvider macroTagProvider, final String... names) {
        parser.getSyntax().addMacroTagProvider(macroTagProvider, names);
        return this;
    }

    /** @param processor updates a field through reflection when a specified actor changes its state.
     * @return this for chaining.
     * @see OnChangeProcessor
     * @see com.github.czyzby.lml.parser.impl.annotation.processor.AbstractOnChangeProcessor */
    public LmlParserBuilder onChangeProcessor(final OnChangeProcessor processor) {
        parser.getData().addOnChangeProcessor(processor);
        return this;
    }

    /** @param strict if false, some template syntax errors will be ignored. Useful for prototyping or planning and
     *            checking unfinished views
     * @return this for chaining. */
    public LmlParserBuilder strict(final boolean strict) {
        parser.setStrict(strict);
        return this;
    }

    /** @param nested if true, regular comments can be nested - basically, comments can contain comments, which isn't
     *            normal HTML behavior. This, however, forces you to keep your comments valid even when they are
     *            "commented out" (otherwise parser doesn't know when to exit from nested comments), so comment macros
     *            are generally preferred to using nested comments.
     * @return this for chaining. */
    public LmlParserBuilder nestedComments(final boolean nested) {
        parser.setNestedComments(nested);
        return this;
    }

    /** @param amount amount of lines (included in exception message) before and after the line that caused the error.
     *            Cannot be negative.
     * @return this for chaining. */
    public LmlParserBuilder debugLinesOnException(final int amount) {
        parser.setLinesAmountPrintedOnException(amount);
        return this;
    }

    /** @param reader determines how LML templates are read. Do not modify unless you are sure what you're doing.
     * @return this for chaining.
     * @see com.github.czyzby.lml.parser.impl.DefaultLmlTemplateReader */
    public LmlParserBuilder templateReader(final LmlTemplateReader reader) {
        parser.setTemplateReader(reader);
        return this;
    }

    /** @param syntax contains the operators, markers, tags, attributes and macros that are parsed and handled by LML
     *            parser. Make sure to register your custom data with {@link #attribute(LmlAttribute, String...)},
     *            {@link #tag(LmlTagProvider, String...)} and {@link #macro(LmlTagProvider, String...)} after invoking
     *            this method, otherwise changes will take places in the previous syntax.
     * @return this for chaining.
     * @see com.github.czyzby.lml.parser.impl.DefaultLmlSyntax */
    public LmlParserBuilder syntax(final LmlSyntax syntax) {
        parser.setSyntax(syntax);
        return this;
    }

    /** @return an instance of {@link LmlParser}. Each builder returns the same instance of each call of this method, so
     *         if you need multiple parsers for any reason, use a separate builder to construct it.
     * @see LmlParser#parseTemplate(String)
     * @see LmlParser#parseTemplate(com.badlogic.gdx.files.FileHandle)
     * @see LmlParser#fillStage(com.badlogic.gdx.scenes.scene2d.Stage, String)
     * @see LmlParser#fillStage(com.badlogic.gdx.scenes.scene2d.Stage, com.badlogic.gdx.files.FileHandle)
     * @see LmlParser#createView(Class, String)
     * @see LmlParser#createView(Object, String)
     * @see LmlParser#createView(Class, com.badlogic.gdx.files.FileHandle)
     * @see LmlParser#createView(Object, com.badlogic.gdx.files.FileHandle) */
    public LmlParser build() {
        return parser;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy