package de.lmu.ifi.dbs.elki.gui.util;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2015
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
import java.util.ArrayList;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.ParameterException;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackedParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.SerializedParameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.TrackParameters;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Parameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.StringParameter;
/**
* Wrapper around a set of parameters for ELKI, that may not yet be complete or
* correct.
*
* @author Erich Schubert
*
* @apiviz.owns de.lmu.ifi.dbs.elki.gui.util.DynamicParameters.RemainingOptions
*/
public class DynamicParameters {
/**
* Bit for an option that should be set
*/
public static final int BIT_INCOMPLETE = 1;
/**
* Bit for an option with an invalid value
*/
public static final int BIT_INVALID = 2;
/**
* Bit for an option containing an syntax error
*/
public static final int BIT_SYNTAX_ERROR = 4;
/**
* Bit for an optional value
*/
public static final int BIT_OPTIONAL = 8;
/**
* Bit for an option with a default value
*/
public static final int BIT_DEFAULT_VALUE = 16;
/**
* Pseudo-value used in dropdowns for options that have a default value
*/
public static final String STRING_USE_DEFAULT = "Default: ";
/**
* Pseudo-value used in options that are optional, to unset.
*/
public static final String STRING_OPTIONAL = "(optional)";
/**
* Node in the option tree (well, actually list)
*
* @author Erich Schubert
*
* @apiviz.exclude
*/
public class Node {
protected Parameter> param;
protected String value;
protected int flags;
protected int depth;
/**
* Constructor.
*
* @param param Parameter
* @param value Value
* @param flags Flags
* @param depth Depth (for tree representation)
*/
public Node(Parameter> param, String value, int flags, int depth) {
super();
this.param = param;
this.value = value;
this.flags = flags;
this.depth = depth;
}
}
/**
* Parameter storage
*/
protected ArrayList parameters;
/**
* Constructor
*/
public DynamicParameters() {
super();
this.parameters = new ArrayList<>();
}
/**
* Get the size
*
* @return number of parameters
*/
public int size() {
return this.parameters.size();
}
/**
* Update the Parameter list from the collected options of an ELKI context
*
* @param track Tracked Parameters
*/
public synchronized void updateFromTrackParameters(TrackParameters track) {
parameters.clear();
for(TrackedParameter p : track.getAllParameters()) {
Parameter> option = p.getParameter();
String value = null;
if(option.isDefined()) {
if(option.tookDefaultValue()) {
value = DynamicParameters.STRING_USE_DEFAULT + option.getDefaultValueAsString();
}
else {
value = option.getValueAsString();
}
}
if(value == null) {
value = (option instanceof Flag) ? Flag.NOT_SET : "";
}
int bits = 0;
if(option.isOptional()) {
bits |= BIT_OPTIONAL;
}
if(option.hasDefaultValue() && option.tookDefaultValue()) {
bits |= BIT_DEFAULT_VALUE;
}
if(value.length() <= 0) {
if((bits & BIT_DEFAULT_VALUE) == 0 && (bits & BIT_OPTIONAL) == 0) {
bits |= BIT_INCOMPLETE;
}
}
else {
try {
if(!option.tookDefaultValue() && !option.isValid(value)) {
bits |= BIT_INVALID;
}
}
catch(ParameterException e) {
bits |= BIT_INVALID;
}
}
int depth = 0;
{
Object pos = track.getParent(option);
while(pos != null) {
pos = track.getParent(pos);
depth += 1;
if(depth > 10) {
break;
}
}
}
parameters.add(new Node(option, value, bits, depth));
}
}
/**
* Add a single parameter to the list
*
* @param option Option
* @param value Value
* @param bits Bits
* @param depth Depth
*/
public synchronized void addParameter(Parameter> option, String value, int bits, int depth) {
parameters.add(new Node(option, value, bits, depth));
}
/**
* Serialize parameters into an array list to pass to setParameters()
*
* @return Array list of String parameters.
*/
public synchronized ArrayList serializeParameters() {
ArrayList p = new ArrayList<>(2 * parameters.size());
for(Node t : parameters) {
if(t.param != null) {
if(t.param instanceof RemainingOptions) {
for(String str : t.value.split(" ")) {
if(str.length() > 0) {
p.add(str);
}
}
}
else if(t.param instanceof Flag) {
if(Flag.SET.equals(t.value)) {
p.add(SerializedParameterization.OPTION_PREFIX + t.param.getOptionID().getName());
}
}
else if(t.value != null && t.value.length() > 0) {
if(!t.value.startsWith(STRING_USE_DEFAULT) && !STRING_OPTIONAL.equals(t.value)) {
p.add(SerializedParameterization.OPTION_PREFIX + t.param.getOptionID().getName());
p.add(t.value);
}
}
}
}
return p;
}
/**
* Get the node in this nth row of the flattened tree.
*
* @param rowIndex row index
* @return tree node
*/
public Node getNode(int rowIndex) {
return this.parameters.get(rowIndex);
}
/**
* OptionID for unrecognized options.
*/
protected static OptionID REMAINING_OPTIONS_ID = new OptionID("UNUSED", "Unrecognized options.");
/**
* Dummy option class that represents unhandled options
*
* @author Erich Schubert
*/
public static class RemainingOptions extends StringParameter {
/**
* Constructor.
*/
public RemainingOptions() {
super(REMAINING_OPTIONS_ID);
super.setOptional(true);
}
}
}