/**
* CertainTrust SDK
*
* Implements the computational trust model "CertainTrust"
* in Java.
* See for further details.
*
*
* Telecooperation Department, Technische Universität Darmstadt
*
*
* Prof. Dr. Max Mühlhäuser
* Florian Volk
*
*
* @author David Kalnischkies
* @author Florian Volk
* @version 1.0
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package CertainTrust;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
/**
* The CertainTrustHTI includes a formular to change
* the C, T and F values of the given CertainTrust
* element and a canvas displaying the expectation
* calculated from these values
*/
public class CertainTrustSimpleHTI extends JPanel implements Observer {
private static final long serialVersionUID = -1194437596328826222L;
/**
* Creates a new HTI to display a CertainTrustSimple element
*
* @param certainlogic element to display
*/
public CertainTrustSimpleHTI(CertainTrustSimple certainlogic) {
setup(certainlogic, null);
}
/**
* Creates a new HTI to display a CertainTrustSimple element
*
* Supported config options are:
* - label.lang: language for the text elements (available: "de" and "en" (default))
* - label.f, label.c, label.t and label.e to set the text explicitly
* - readonly: to effect the complete HTI (value either "true" or "false") and
* - readonly.f, readonly.c, readonly.t, readonly.e to set explicitly
* See also {@link CertainTrustCanvas#CertainTrustCanvas(CertainTrust, Map)} for
* additional options which are accepted by the canvas element
*
* @param certainlogic element to display
* @param config to use for this HTI
*/
public CertainTrustSimpleHTI(CertainTrustSimple certainlogic, Map config) {
setup(certainlogic, config);
}
private CertainTrustSimple cl;
private JTextField f;
private JTextField c;
private JTextField t;
private JTextField e;
private CertainTrustSimpleCanvas ctc;
private Map config;
protected CertainTrustSimpleCanvas getCanvas() { return ctc; }
private static JTextField appendInput(JPanel p, String name, char mnemonic, double value, String readOnly, CertainTrustActionFocusListener listener) {
JLabel l = new JLabel(name);
l.setBorder(new EmptyBorder(0, 0, 0, (int) (l.getFont().getSize() * 1.5)));
final JTextField f = new JTextField(CertainTrustSimpleHTI.formatFloat(value), 4);
if (readOnly.compareToIgnoreCase("true") == 0) {
f.setEditable(false);
f.setFocusable(false);
}
else if (readOnly.compareToIgnoreCase("false") != 0)
throw new IllegalArgumentException("Input element " + name + " has no valid readonly setting");
else if (listener != null) {
f.addActionListener(listener);
f.addFocusListener(listener);
}
l.setLabelFor(f);
if (mnemonic != '\0')
l.setDisplayedMnemonic(mnemonic);
p.add(l);
p.add(f);
return f;
}
private abstract class CertainTrustActionFocusListener implements ActionListener, FocusListener {
@Override
public void focusGained(FocusEvent arg0) {}
@Override
public void focusLost(FocusEvent arg0) {
update();
}
@Override
public void actionPerformed(ActionEvent arg0) {
update();
}
abstract void update();
/**
* parseInput tries to convert a textual input into a floating point number in [0;1]
* It accepts both "." and "," as decimal delimiters.
* If the conversion fails, a default value is used.
* @param input the textual input to convert into a floating point number
* @param defaultValue the default value used in case the conversion fails
* @return the floating point value generated from the textual input
*/
protected double parseInput(String input, double defaultValue) {
double result;
try {
// first, replace the first "," with a "." to understand German-language style floating point notation
String rawInput = input.replaceFirst(",", ".");
result = Double.parseDouble(rawInput);
// check, if the value in within our bounds of [0;1]
if ((1 < result) || (0 > result)) {
result = defaultValue;
}
}
catch (NumberFormatException e) {
result = defaultValue;
}
return result;
}
}
private void setup(CertainTrustSimple certainlogic, Map config) {
cl = certainlogic;
if (config != null)
this.config = config;
else
this.config = new HashMap();
if (this.config.containsKey("label.lang") == false)
this.config.put("label.lang", "en");
if (this.config.get("label.lang") == "de") {
if (this.config.containsKey("label.f") == false)
this.config.put("label.f", "Initialwert");
if (this.config.containsKey("label.t") == false)
this.config.put("label.t", "Vertrauen");
if (this.config.containsKey("label.c") == false)
this.config.put("label.c", "Sicherheit");
if (this.config.containsKey("label.e") == false)
this.config.put("label.e", "Erwartung");
} else {
if (this.config.containsKey("label.f") == false)
this.config.put("label.f", "Init. value");
if (this.config.containsKey("label.t") == false)
this.config.put("label.t", "Trust");
if (this.config.containsKey("label.c") == false)
this.config.put("label.c", "Certainty");
if (this.config.containsKey("label.e") == false)
this.config.put("label.e", "Expectation");
}
if (this.config.containsKey("readonly") == false) {
if (this.config.containsKey("readonly.f") == false)
this.config.put("readonly.f", "false");
if (this.config.containsKey("readonly.t") == false)
this.config.put("readonly.t", "false");
if (this.config.containsKey("readonly.c") == false)
this.config.put("readonly.c", "false");
if (this.config.containsKey("readonly.e") == false)
this.config.put("readonly.e", "true");
} else {
String readOnly = this.config.get("readonly");
if (this.config.containsKey("readonly.f") == false)
this.config.put("readonly.f", readOnly);
if (this.config.containsKey("readonly.t") == false)
this.config.put("readonly.t", readOnly);
if (this.config.containsKey("readonly.c") == false)
this.config.put("readonly.c", readOnly);
if (this.config.containsKey("readonly.e") == false)
this.config.put("readonly.e", readOnly);
}
JPanel inputs = new JPanel(new GridLayout(5,2));
f = appendInput(inputs, this.config.get("label.f"), 'f', cl.getF(), this.config.get("readonly.f"),
new CertainTrustActionFocusListener() {
@Override
void update() {
cl.setF(this.parseInput(f.getText(), cl.getF()));
}
});
t = appendInput(inputs, this.config.get("label.t"), 't', cl.getT(), this.config.get("readonly.t"),
new CertainTrustActionFocusListener() {
@Override
void update() {
cl.setTC(this.parseInput(t.getText(), cl.getT()),
cl.getC());
}
});
c = appendInput(inputs, this.config.get("label.c"), 'c', cl.getC(), this.config.get("readonly.c"),
new CertainTrustActionFocusListener() {
@Override
void update() {
cl.setTC(cl.getT(),
this.parseInput(c.getText(), cl.getC()));
}
});
JLabel ignore0 = new JLabel("");
inputs.add(ignore0);
JLabel ignore1 = new JLabel("");
inputs.add(ignore1);
e = appendInput(inputs, this.config.get("label.e"),'\0', cl.getExpectation(), this.config.get("readonly.e"), null);
this.add(inputs);
JPanel jp = new JPanel();
jp.setLayout(new BoxLayout(jp, BoxLayout.PAGE_AXIS));
JPanel jp1 = new JPanel();
JLabel certain = new JLabel(this.config.get("label.c") + "\u00a0\u2192");
certain.setUI(new VerticalLabelUI());
jp1.add(certain);
ctc = new CertainTrustSimpleCanvas(cl, this.config);
ctc.repaint();
jp1.add(ctc);
JPanel jp2 = new JPanel(new BorderLayout());
JLabel origin = new JLabel("0");
int fontsize = certain.getFont().getSize();
origin.setBorder(new EmptyBorder(0, fontsize, 0, fontsize));
jp2.add(origin, BorderLayout.LINE_START);
JLabel trust = new JLabel(this.config.get("label.t") + "\u00a0\u2192");
jp2.add(trust, BorderLayout.CENTER);
jp.add(jp1);
jp.add(jp2);
this.add(jp);
this.setVisible(true);
cl.addObserver(this);
}
@Override
public void update(Observable ignored0, Object ignored1) {
f.setText(CertainTrustSimpleHTI.formatFloat(cl.getF()));
t.setText(CertainTrustSimpleHTI.formatFloat(cl.getT()));
c.setText(CertainTrustSimpleHTI.formatFloat(cl.getC()));
e.setText(CertainTrustSimpleHTI.formatFloat(cl.getExpectation()));
}
/**
* Rounds a number to at most 3 decimal places and converts it to a string
* @param value the number to round
* @return the rounded value as string
*/
static private String formatFloat(double value) {
// the explicit type cast from Long to double is required, otherwise rounded will always be 0
double rounded = ((double)Math.round(value * 1000) / 1000);
// Use NumerFormat to omit trailing 0s as those which Double.toString() produces
NumberFormat formatter = new DecimalFormat("0.###");
String result = formatter.format(rounded);
// for compatibility with the JS version, our decimal delimiter *always* is "."
result = result.replaceFirst(",", ".");
return result;
}
}