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

de.tsl2.nano.incubation.terminal.item.Container Maven / Gradle / Ivy

Go to download

TSL2 Framework Terminal (Console Application Framework named SIShell, providing Actions, Options, Commands, Inputs, lots of Selectors, PlatformManagement)

There is a newer version: 2.5.2
Show newest version
/*
 * File: $HeadURL$
 * Id  : $Id$
 * 
 * created by: Tom
 * created on: 24.12.2014
 * 
 * Copyright: (c) Thomas Schneider 2014, all rights reserved
 */
package de.tsl2.nano.incubation.terminal.item;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.core.Commit;

import de.tsl2.nano.action.IConstraint;
import de.tsl2.nano.collection.CollectionUtil;
import de.tsl2.nano.core.ENV;
import de.tsl2.nano.core.IPredicate;
import de.tsl2.nano.core.util.StringUtil;
import de.tsl2.nano.core.util.Util;
import de.tsl2.nano.incubation.terminal.IContainer;
import de.tsl2.nano.incubation.terminal.IItem;
import de.tsl2.nano.incubation.terminal.SIShell;

/**
 * the Container of items. if only one item is available, it should delegate the request directly to that item.
 * 
 * @author Tom
 * @version $Revision$
 */
@SuppressWarnings("rawtypes")
public class Container extends AItem implements IContainer {

    /** serialVersionUID */
    private static final long serialVersionUID = -3656677742608173033L;

    /** child nodes */
    @ElementList(type = AItem.class, inline = true, entry = "item", required = false)
    protected List> nodes;

    transient private boolean isactive;
    /** (default:true) if true, result (=value) is a collection! */
    @Attribute(required = false)
    boolean multiple = false;
    /** if true, all tree items will be accessed directly and sequentially */
    @Attribute(required=false)
    boolean sequential = false;
    /** on sequential mode, this index points to the actual child-item */
    transient int seqIndex = -1;

    /**
     * constructor
     */
    public Container() {
        super();
        //WORKAROUND: unable to save list of values through simple-xml
        value = (T) (multiple ? new ArrayList() : value);
        type = Type.Container;
        prefix.setCharAt(PREFIX, '+');
        initNodes();
    }

    public Container(String name, String description) {
        this(name, null, null, description);
    }

    /**
     * constructor
     * 
     * @param name
     * @param constraints
     * @param type
     * @param value
     */
    public Container(String name, IConstraint constraints, List selected, String description) {
        super(name, constraints, Type.Container, (T) selected, description);
        multiple = selected != null;
        initNodes();
        prefix.setCharAt(PREFIX, '+');
    }

    protected void initNodes() {
        nodes = new ArrayList>();
    }

    protected List> getNodes() {
        return nodes;
    }

    /**
     * filters all child nodes where the condition return false
     * 
     * @param context application context
     * @return filtered child nodes
     */
    @Override
    public List> getNodes(final Map context) {
        return CollectionUtil.getFiltering(nodes, new IPredicate>() {
            @Override
            public boolean eval(AItem arg0) {
                return arg0.getCondition() == null || arg0.getCondition().isTrue(context);
            }
        });
    }

    /**
     * if the selected child is again of type tree but has only one active child, this child will be activated.
     * 
     * @param selected selected child
     * @param in input
     * @param out output
     * @param env application context
     * @return the selected item, or if it is a tree having only one active child - this child
     */
    public IItem delegateToUniqueChild(IItem selected, InputStream in, PrintStream out, Properties env) {
        if (selected.getType() == Type.Container && ((Container) selected).getNodes(env).size() == 1) {
            //if only one tree child is available, delegate directly to that item
            return selected.react(this, "1", in, out, env);
        } else {
            return selected;
        }
    }

    @Override
    protected void initConstraints(IConstraint constraints) {
    }

    @Override
//    @Transient
    //WORKAROUND: unable to save list of values through simple-xml
//    @ElementList(type=Object.class, inline = true, entry = "value", required = false)
    public T getValue() {
        return value;
    }

    @Override
//    @Transient
    //WORKAROUND: unable to save list of values through simple-xml
//    @ElementList(type=Object.class, inline = true, entry = "value", required = false)
    public void setValue(T value) {
        super.setValue(value);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public T getValue(int i) {
        return multiple ? ((List) value).get(i) : value;
    }

    @Override
    public String ask(Properties env) {
        isactive = true;
        List> children = getNodes(env);
        return isSequential() && seqIndex > -1 && seqIndex < children.size() ? children.get(seqIndex).ask(env)
            : ENV.translate("ask.number", false)
                + children.size() + POSTFIX_QUESTION;
    }

    public boolean isSequential() {
        return sequential || (Boolean)System.getProperties().get(SIShell.KEY_SEQUENTIAL);
    }
    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    public IItem react(IItem caller, String input, InputStream in, PrintStream out, Properties env) {
        if (Util.isEmpty(input) && !isSequential()) {
            return getParent();
        }
        IItem next = null;
        List> filteredNodes = getNodes(env);
        /*
         * sequential mode
         */
        if (isSequential() && seqIndex < filteredNodes.size()) {
            return next(in, out, env);
        }

        /*
         * standard menu selection mode
         */
        //find the item through current user input
        next = getNode(input, env);

        IItem nextnext = null;
        if (!next.isEditable()) {
            nextnext = next.react(this, Util.asString(next.getValue()), in, out, env);
        } else if (next instanceof IContainer && ((Container) next).getNodes(env).size() == 1) {
            //if only one tree child is available, delegate directly to that item
            nextnext = next.react(this, "1", in, out, env);
        }
        //assign the new result
        if (multiple) {
            ((List) value).add((T) next.getValue());
        } else {
            setValue((T) next.getValue());
        }

        if (getValue() != null) {
            env.put(getName(), getValue());
        }
        isactive = false;
        return nextnext != null ? nextnext : next;
    }

    public IItem getNode(String input, Properties env) {
        if (input.matches("\\d+")) {
            //input: one-based index
            return getNodes(env).get(Integer.valueOf(input) - 1);
        } else {
            List> childs = getNodes(env);
            input = input.toLowerCase();
            for (IItem i : childs) {
                if (i.getName().toLowerCase().startsWith(input)) {
                    return i;
                }
            }
            throw new IllegalArgumentException(input + " is not a known value!");
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean add(IItem item) {
        item.setParent(this);
        return getNodes().add((AItem) item);
    }

    @Override
    public boolean remove(IItem item) {
        item.setParent(this);
        return getNodes().remove(item);
    }

    public void setMultiple(boolean multiple) {
        this.multiple = multiple;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public IItem next(InputStream in, PrintStream out, Properties env) {
        IItem next;
        if (isSequential()) {
            if (++seqIndex < getNodes(env).size()) {
                next = getNodes(env).get(seqIndex);
                //ask for all tree items
                if (next.getType() == Type.Container) {
                    return next.react(this, null, in, out, env);
                } else {
                    return next;
                }
            } else {
//                sequential = false;
//                seqIndex = -1;
                next = getParent().next(in, out, env);
            }
        } else {
            next = this;
        }
        return next;
    }

    @Override
    @Commit
    protected void initDeserialization() {
        super.initDeserialization();
        //fill yourself as parent for all children
        if (getNodes() != null) {
            for (IItem n : getNodes()) {
                n.setParent(this);
            }
        } else {
            initNodes();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getDescription(Properties env, boolean full) {
        if (isactive || isSequential()) {
            String img = null;
            List> list = getNodes(env);
            if (hasFileDescription()) {
                if (isSequential())
                    return super.getDescription(env, full);
                else {
                    int height = Util.get(SIShell.KEY_HEIGHT, 20);
                    img = printImageDescription(height - (list.size() >= height ? 0 : list.size()));
                }
            }
            StringBuilder buf = img != null ? new StringBuilder(img) : new StringBuilder(list.size() * 60);
            int i = 0;
            //evaluate key string length for formatted output
            int kl = 0;
            for (IItem t : list) {
                kl = Math.max(kl, ((AItem) t).getName(-1, (char) -1).length());
            }
            kl++;
            int vwidth = Util.get(SIShell.KEY_WIDTH, 80) - (kl + 9);
            //print the child item list
            int s = String.valueOf(list.size()).length() + 1;
            for (AItem t : list) {
                buf.append(StringUtil.fixString(String.valueOf(++i), s, ' ', false)
                    + "."
                    + t.getName(kl, ' ')
                    + POSTFIX_QUESTION
                    + (full && !t.getType().equals(Type.Container) ? t.getDescription(env, full) : StringUtil.toString(
                        t.getValueText().replace('\n', ' '), vwidth))
                    + "\n");
            }
            return buf.toString();
        } else {
            return getName(-1, (char) -1) + "\n";
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy