
de.tsl2.nano.incubation.terminal.item.Container Maven / Gradle / Ivy
/*
* 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 - 2025 Weber Informatics LLC | Privacy Policy