Base Complete
This commit is contained in:
parent
593e489b3a
commit
ae3cd5a578
|
@ -4,6 +4,8 @@ import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
|
@ -17,9 +19,18 @@ public abstract class AbstractNode implements Node
|
||||||
{
|
{
|
||||||
/** Content-Panel */
|
/** Content-Panel */
|
||||||
protected final JPanel content;
|
protected final JPanel content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backing Set for Change Listeners!
|
||||||
|
*/
|
||||||
|
public final CopyOnWriteArraySet<Consumer<Node>> listeners = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
private final JPanel main;
|
private final JPanel main;
|
||||||
|
/** The parent node */
|
||||||
|
protected Node parent = null;
|
||||||
|
|
||||||
private final JPanel sub;
|
private final JPanel sub;
|
||||||
|
|
||||||
/** Sub-Nodes */
|
/** Sub-Nodes */
|
||||||
protected final LinkedHashSet<Node> subNodes = new LinkedHashSet<>();
|
protected final LinkedHashSet<Node> subNodes = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
@ -31,11 +42,14 @@ public abstract class AbstractNode implements Node
|
||||||
main = new JPanel(true);
|
main = new JPanel(true);
|
||||||
main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
|
main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
|
||||||
main.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
main.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
||||||
|
main.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
|
||||||
content = new JPanel(new BorderLayout(), true);
|
content = new JPanel(new BorderLayout(), true);
|
||||||
|
content.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
sub = new JPanel(true);
|
sub = new JPanel(true);
|
||||||
sub.setLayout(new BoxLayout(sub, BoxLayout.Y_AXIS));
|
sub.setLayout(new BoxLayout(sub, BoxLayout.Y_AXIS));
|
||||||
sub.setBorder(new EmptyBorder(0, 16, 4, 0));
|
sub.setBorder(new EmptyBorder(0, 16, 4, 0));
|
||||||
|
sub.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
|
||||||
main.add(content);
|
main.add(content);
|
||||||
main.add(sub);
|
main.add(sub);
|
||||||
|
@ -46,9 +60,16 @@ public abstract class AbstractNode implements Node
|
||||||
*/
|
*/
|
||||||
protected abstract void _reset();
|
protected abstract void _reset();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addChangeListener(Consumer<Node> c)
|
||||||
|
{
|
||||||
|
listeners.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSubNode(Node n)
|
public void addSubNode(Node n)
|
||||||
{
|
{
|
||||||
|
n.setParentNode(this);
|
||||||
subNodes.add(n);
|
subNodes.add(n);
|
||||||
sub.add(n.getComponent());
|
sub.add(n.getComponent());
|
||||||
}
|
}
|
||||||
|
@ -61,10 +82,28 @@ public abstract class AbstractNode implements Node
|
||||||
public LinkedHashSet<Node> getSubNodes()
|
public LinkedHashSet<Node> getSubNodes()
|
||||||
{ return subNodes; }
|
{ return subNodes; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(Node n)
|
||||||
|
{
|
||||||
|
if (parent != null)
|
||||||
|
{
|
||||||
|
parent.onChange(n);
|
||||||
|
}
|
||||||
|
listeners.forEach(e -> e.accept(n));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
_reset();
|
_reset();
|
||||||
subNodes.forEach(Node::reset);
|
subNodes.forEach(Node::reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParentNode(Node n) throws IllegalStateException
|
||||||
|
{
|
||||||
|
if (parent != null)
|
||||||
|
{ throw new IllegalStateException("Parent already set!"); }
|
||||||
|
parent = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.ButtonGroup;
|
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import javax.swing.JLabel;
|
||||||
public class CheckboxMultiSelect extends AbstractNode
|
public class CheckboxMultiSelect extends AbstractNode
|
||||||
{
|
{
|
||||||
private final String baseMsg;
|
private final String baseMsg;
|
||||||
private final ButtonGroup bg;
|
|
||||||
private final BigDecimal maxPoints;
|
private final BigDecimal maxPoints;
|
||||||
private final BigDecimal[] points;
|
private final BigDecimal[] points;
|
||||||
|
|
||||||
|
@ -27,57 +26,62 @@ public class CheckboxMultiSelect extends AbstractNode
|
||||||
public CheckboxMultiSelect(String config)
|
public CheckboxMultiSelect(String config)
|
||||||
{
|
{
|
||||||
var lines = config.split("\n");
|
var lines = config.split("\n");
|
||||||
|
if (lines.length <= 1)
|
||||||
|
{ throw new IllegalArgumentException("Not enough lines!"); }
|
||||||
var spl0 = lines[0].split("\t");
|
var spl0 = lines[0].split("\t");
|
||||||
if (!"\\\\".equals(spl0[0]))
|
if (!"\\\\".equals(spl0[0]))
|
||||||
{ throw new IllegalArgumentException("Expected \\\\"); }
|
{ throw new IllegalArgumentException("Expected \\\\"); }
|
||||||
if (spl0.length != 2 && spl0.length != 3)
|
if (spl0.length != 3)
|
||||||
{ throw new IllegalArgumentException("Expected 1 or 2 \\t"); }
|
{ throw new IllegalArgumentException("Expected 1 or 2 \\t"); }
|
||||||
maxPoints = new BigDecimal(spl0[1]);
|
maxPoints = new BigDecimal(spl0[1]);
|
||||||
if (maxPoints.signum() <= 0)
|
if (maxPoints.signum() <= 0)
|
||||||
{ throw new IllegalArgumentException("Positive Points required! got: " + maxPoints); }
|
{ throw new IllegalArgumentException("Positive Points required! got: " + maxPoints); }
|
||||||
baseMsg = spl0.length == 3 ? spl0[2] : null;
|
baseMsg = spl0[2];
|
||||||
points = new BigDecimal[lines.length - 1];
|
points = new BigDecimal[lines.length - 1];
|
||||||
text = new String[lines.length - 1];
|
text = new String[lines.length - 1];
|
||||||
rbs = new JCheckBox[lines.length - 1];
|
rbs = new JCheckBox[lines.length - 1];
|
||||||
bg = new ButtonGroup();
|
|
||||||
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
|
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
|
||||||
if (baseMsg != null)
|
if (baseMsg != null)
|
||||||
{
|
{
|
||||||
content.add(new JLabel(baseMsg));
|
content.add(new JLabel(baseMsg));
|
||||||
}
|
}
|
||||||
|
ActionListener cl = e -> onChange(this);
|
||||||
for (var i = 1; i < lines.length; i++)
|
for (var i = 1; i < lines.length; i++)
|
||||||
{
|
{
|
||||||
var s = lines[i].split("\t");
|
var s = lines[i].substring(1).split("\t");
|
||||||
if (s.length != 2)
|
if (s.length != 3)
|
||||||
{ throw new IllegalArgumentException("Expected exactly 1 \\t"); }
|
{ throw new IllegalArgumentException("Expected exactly 2 \\t"); }
|
||||||
points[i - 1] = new BigDecimal(s[0]);
|
if (!"[]".equals(s[0]))
|
||||||
text[i - 1] = s[1];
|
{ throw new IllegalArgumentException("Expected []"); }
|
||||||
rbs[i - 1] = new JCheckBox(text[i - 1]);
|
points[i - 1] = new BigDecimal(s[1]);
|
||||||
|
text[i - 1] = s[2];
|
||||||
|
rbs[i - 1] = new JCheckBox(Utils.ptsToString(points[i - 1]) + "P - " + text[i - 1]);
|
||||||
|
rbs[i - 1].addActionListener(cl);
|
||||||
content.add(rbs[i - 1]);
|
content.add(rbs[i - 1]);
|
||||||
bg.add(rbs[i - 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void _reset()
|
protected void _reset()
|
||||||
{
|
{
|
||||||
bg.clearSelection();
|
for (var e : rbs)
|
||||||
|
{
|
||||||
|
e.setSelected(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal achievedPoints(MathContext mc)
|
public BigDecimal achievedPoints(MathContext mc)
|
||||||
{
|
{
|
||||||
return points[getSelected()];
|
var bd = BigDecimal.ZERO;
|
||||||
}
|
|
||||||
|
|
||||||
private int getSelected()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < rbs.length; i++)
|
for (var i = 0; i < rbs.length; i++)
|
||||||
{
|
{
|
||||||
if (rbs[i].isSelected())
|
if (rbs[i].isSelected())
|
||||||
{ return i; }
|
{
|
||||||
|
bd = bd.add(points[i], mc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rbs.length - 1;
|
return bd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,7 +107,7 @@ public class CheckboxMultiSelect extends AbstractNode
|
||||||
}
|
}
|
||||||
for (var i = 0; i < text.length; i++)
|
for (var i = 0; i < text.length; i++)
|
||||||
{
|
{
|
||||||
sb.append("\n\t");
|
sb.append("\n\t[]\t");
|
||||||
sb.append(points[i].toPlainString());
|
sb.append(points[i].toPlainString());
|
||||||
sb.append("\t");
|
sb.append("\t");
|
||||||
sb.append(text[i]);
|
sb.append(text[i]);
|
||||||
|
@ -114,10 +118,24 @@ public class CheckboxMultiSelect extends AbstractNode
|
||||||
@Override
|
@Override
|
||||||
public String toResultHtml(HtmlContext hc)
|
public String toResultHtml(HtmlContext hc)
|
||||||
{
|
{
|
||||||
return "<li" + hc.styleText(achievedPoints(hc.mc), maxPoints) + ">" + //
|
var sb = new StringBuilder();
|
||||||
"<span" + hc.stylePts(achievedPoints(hc.mc), maxPoints) + ">" + //
|
sb.append("<li").append(hc.styleText(achievedPoints(hc.mc), maxPoints)).append(">");
|
||||||
achievedPoints(hc.mc) + "/" + maxPoints.toPlainString() + "P</span>" + //
|
sb.append("<span").append(hc.stylePts(achievedPoints(hc.mc), maxPoints)).append(">");
|
||||||
(baseMsg == null ? text[getSelected()] : baseMsg + " (" + text[getSelected()] + ")") + "</li>";
|
sb.append(achievedPoints(hc.mc)).append(" / ").append(maxPoints.toPlainString());
|
||||||
|
sb.append("P</span> ");
|
||||||
|
sb.append(baseMsg);
|
||||||
|
sb.append("\n\t<ul style=\"list-style-type: none;margin-top: 0px;margin-bottom:0px\">\n");
|
||||||
|
for (var i = 0; i < rbs.length; i++)
|
||||||
|
{
|
||||||
|
sb.append("\t\t<li").append(hc.cbx(rbs[i])).append(">");
|
||||||
|
sb.append(rbs[i].isSelected() ? "✓ " : "✗ ");
|
||||||
|
sb.append("(").append(points[i].toPlainString()).append("P) ");
|
||||||
|
sb.append(text[i]);
|
||||||
|
sb.append("</li>\n");
|
||||||
|
}
|
||||||
|
sb.append("\t</ul>\n");
|
||||||
|
sb.append("</li>");
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class CheckboxNode extends AbstractNode
|
||||||
points = new BigDecimal(spl[1]);
|
points = new BigDecimal(spl[1]);
|
||||||
message = spl[2];
|
message = spl[2];
|
||||||
cbx = new JCheckBox(Utils.ptsToString(points) + "P " + message);
|
cbx = new JCheckBox(Utils.ptsToString(points) + "P " + message);
|
||||||
|
cbx.addActionListener(e -> onChange(this));
|
||||||
content.add(cbx);
|
content.add(cbx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ public class CheckboxNode extends AbstractNode
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVisibleInResultHtml()
|
public boolean isVisibleInResultHtml()
|
||||||
{ return cbx.isSelected(); }
|
{ return cbx.isSelected() || subNodes.stream().anyMatch(Node::isVisibleInResultHtml); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal maximumPoints()
|
public BigDecimal maximumPoints()
|
||||||
|
@ -66,7 +67,7 @@ public class CheckboxNode extends AbstractNode
|
||||||
public String toResultHtml(HtmlContext hc)
|
public String toResultHtml(HtmlContext hc)
|
||||||
{
|
{
|
||||||
return "<li" + hc.styleText(points.signum()) + "><span" + hc.stylePts(points.signum()) + ">"
|
return "<li" + hc.styleText(points.signum()) + "><span" + hc.stylePts(points.signum()) + ">"
|
||||||
+ Utils.ptsToString(achievedPoints(hc.mc)) + "P</span>" + message + "</li>";
|
+ Utils.ptsToString(achievedPoints(hc.mc)) + "P</span> " + message + "</li>";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ public class EitherNode extends AbstractNode
|
||||||
btn_ok = new JRadioButton(Utils.ptsToString(BigDecimal.ZERO) + "P " + messageOK);
|
btn_ok = new JRadioButton(Utils.ptsToString(BigDecimal.ZERO) + "P " + messageOK);
|
||||||
btn_fail = new JRadioButton(Utils.ptsToString(points) + "P " + (messageFail == null ? messageOK : messageFail));
|
btn_fail = new JRadioButton(Utils.ptsToString(points) + "P " + (messageFail == null ? messageOK : messageFail));
|
||||||
}
|
}
|
||||||
|
btn_ok.addActionListener(e -> onChange(this));
|
||||||
|
btn_fail.addActionListener(e -> onChange(this));
|
||||||
|
|
||||||
bg = new ButtonGroup();
|
bg = new ButtonGroup();
|
||||||
bg.add(btn_ok);
|
bg.add(btn_ok);
|
||||||
|
@ -122,7 +124,7 @@ public class EitherNode extends AbstractNode
|
||||||
"<span" + hc.stylePts(signum) + ">" + //
|
"<span" + hc.stylePts(signum) + ">" + //
|
||||||
Utils.ptsToString(achievedPoints(hc.mc)) + //
|
Utils.ptsToString(achievedPoints(hc.mc)) + //
|
||||||
(points.signum() < 0 ? "" : " / " + maximumPoints()) + "P" + //
|
(points.signum() < 0 ? "" : " / " + maximumPoints()) + "P" + //
|
||||||
"</span>" + //
|
"</span> " + //
|
||||||
(btn_fail.isSelected() ? btn_fail.getText() : btn_ok.getText()) + //
|
(btn_fail.isSelected() ? btn_fail.getText() : btn_ok.getText()) + //
|
||||||
"</li>";
|
"</li>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,23 @@ package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pingger
|
* @author Pingger
|
||||||
*/
|
*/
|
||||||
public class HtmlContext
|
public class HtmlContext
|
||||||
{
|
{
|
||||||
|
/** Style for unchecked Boxes in CheckboxMultiSelect */
|
||||||
|
public String cbmsFail = "";
|
||||||
|
/** Style for checked Boxes in CheckboxMultiSelect */
|
||||||
|
public String cbmsOk = "";
|
||||||
/** Style for the Points, when the best case Points have been achieved */
|
/** Style for the Points, when the best case Points have been achieved */
|
||||||
public String fullPtsStyle = "";
|
public String fullPtsStyle = "";
|
||||||
/** Style for the Text, when the best case Points have been achieved */
|
/** Style for the Text, when the best case Points have been achieved */
|
||||||
public String fullPtsTextStyle = "";
|
public String fullPtsTextStyle = "";
|
||||||
/** {@link MathContext} for Output */
|
/** {@link MathContext} for Output */
|
||||||
public MathContext mc;
|
public MathContext mc = MathContext.DECIMAL32;
|
||||||
/** Style for the Points, when the worst case Points have been achieved */
|
/** Style for the Points, when the worst case Points have been achieved */
|
||||||
public String noPtsStyle = "";
|
public String noPtsStyle = "";
|
||||||
/** Style for the Text, when the best case Points have been achieved */
|
/** Style for the Text, when the best case Points have been achieved */
|
||||||
|
@ -30,6 +36,16 @@ public class HtmlContext
|
||||||
*/
|
*/
|
||||||
public String partialPtsTextStyle = "";
|
public String partialPtsTextStyle = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param jCheckBox the checkbox to get the style for
|
||||||
|
* @return the style tag parameter for the checkbox
|
||||||
|
*/
|
||||||
|
public Object cbx(JCheckBox jCheckBox)
|
||||||
|
{
|
||||||
|
return jCheckBox.isSelected() ? cbmsOk.isBlank() ? "" : " style=\"" + cbmsOk + "\""
|
||||||
|
: cbmsFail.isBlank() ? "" : " style=\"" + cbmsFail + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param got achieved Points
|
* @param got achieved Points
|
||||||
* @param max maximum Points
|
* @param max maximum Points
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pingger
|
* @author Pingger
|
||||||
|
@ -8,16 +22,209 @@ import java.io.IOException;
|
||||||
public class KorrekturHelper
|
public class KorrekturHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private static String indentBuffer = "\t";
|
||||||
|
|
||||||
|
private static int getIndent(String line)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < line.length(); i++)
|
||||||
|
{
|
||||||
|
if (line.charAt(i) != '\t')
|
||||||
|
{ return i; }
|
||||||
|
}
|
||||||
|
return line.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String indent(int n)
|
||||||
|
{
|
||||||
|
while (indentBuffer.length() < n)
|
||||||
|
{
|
||||||
|
indentBuffer += indentBuffer;
|
||||||
|
}
|
||||||
|
return indentBuffer.substring(indentBuffer.length() - n);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param args [0] input File
|
* @param args [0] input File
|
||||||
* @throws IOException in case reading the input file fails
|
* @throws IOException in case reading the input file fails
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws IOException
|
public static void main(String[] args) throws IOException
|
||||||
{
|
{
|
||||||
var in = KorrekturHelper.class.getClassLoader()
|
try (
|
||||||
.getResourceAsStream("de/tuDortmund/cs/rvs/pingger/korrekturHelper/Test.schema");
|
var in = KorrekturHelper.class.getClassLoader()
|
||||||
in.transferTo(System.out);
|
.getResourceAsStream("de/tuDortmund/cs/rvs/pingger/korrekturHelper/Test.schema");
|
||||||
in.close();
|
var isr = new InputStreamReader(in, StandardCharsets.UTF_8);
|
||||||
|
var br = new BufferedReader(isr, 1024 * 1024)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var x = parseSchema(br);
|
||||||
|
var frm = new JFrame("Test");
|
||||||
|
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
var panel = new JPanel(true);
|
||||||
|
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||||
|
var jsp = new JScrollPane(panel);
|
||||||
|
Consumer<Node> c = n -> {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
recursiveToHtml(x, sb, new HtmlContext(), 0);
|
||||||
|
System.out.println(sb);
|
||||||
|
};
|
||||||
|
for (var n : x)
|
||||||
|
{
|
||||||
|
n.addChangeListener(c);
|
||||||
|
panel.add(n.getComponent());
|
||||||
|
}
|
||||||
|
frm.setContentPane(jsp);
|
||||||
|
frm.pack();
|
||||||
|
frm.setVisible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LinkedHashSet<Node> parseNodes(String[] lines, int[] lineMap) throws IOException
|
||||||
|
{
|
||||||
|
var roots = new LinkedHashSet<Node>();
|
||||||
|
var path = new LinkedList<Node>();
|
||||||
|
for (var li = 0; li < lines.length; li++)
|
||||||
|
{
|
||||||
|
var line = lines[li];
|
||||||
|
var cmd = line.substring(path.size()).split("\t", 2)[0];
|
||||||
|
System.out.println(indent(path.size()) + lineMap[li] + " - " + cmd + " - " + line);
|
||||||
|
var n = switch (cmd)
|
||||||
|
{
|
||||||
|
case "!header": // !header # Test-Schema
|
||||||
|
yield new HeaderNode(line.substring(path.size()));
|
||||||
|
|
||||||
|
case "[]": // [] -0.5 Punktabzug
|
||||||
|
yield new CheckboxNode(line.substring(path.size()));
|
||||||
|
|
||||||
|
case "\\": // \ 1.0 Element existiert | Element existiert nicht
|
||||||
|
yield new EitherNode(line.substring(path.size()));
|
||||||
|
|
||||||
|
case "\\\\": // \\ MultiSelects
|
||||||
|
if (lines.length <= li)
|
||||||
|
{ throw new IOException("Unexpected EOF"); }
|
||||||
|
var sb = new StringBuilder(line.substring(path.size()));
|
||||||
|
var i = li + 1;
|
||||||
|
for (; i < lines.length; i++)
|
||||||
|
{
|
||||||
|
System.out.println(indent(path.size() + 1) + lineMap[i] + " - " + cmd + " - " + lines[i]);
|
||||||
|
System.out.println(getIndent(lines[i]) + " - " + path.size());
|
||||||
|
if (getIndent(lines[i]) != path.size() + 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sb.append("\n").append(lines[i].substring(path.size()));
|
||||||
|
}
|
||||||
|
if (lines[li + 1].trim().startsWith("[]"))
|
||||||
|
{
|
||||||
|
li = i - 1;
|
||||||
|
yield new CheckboxMultiSelect(sb.toString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
li = i - 1;
|
||||||
|
yield new RadioMultiSelect(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
case "":
|
||||||
|
throw new IOException("Indentation Error on Line " + lineMap[li] + "!");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IOException("Unknown Command: " + cmd);
|
||||||
|
};
|
||||||
|
if (!path.isEmpty())
|
||||||
|
{
|
||||||
|
path.getLast().addSubNode(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
roots.add(n);
|
||||||
|
}
|
||||||
|
if (lines.length > li + 1)
|
||||||
|
{
|
||||||
|
if (getIndent(lines[li + 1]) > path.size())
|
||||||
|
{
|
||||||
|
path.addLast(n);
|
||||||
|
}
|
||||||
|
while (getIndent(lines[li + 1]) < path.size())
|
||||||
|
{
|
||||||
|
path.removeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LinkedHashSet<Node> parseSchema(BufferedReader br) throws IOException
|
||||||
|
{
|
||||||
|
var lineMap = new ArrayList<Integer>();
|
||||||
|
var nodeLines = new ArrayList<String>();
|
||||||
|
String line;
|
||||||
|
var lineNumber = 0;
|
||||||
|
while ((line = br.readLine()) != null)
|
||||||
|
{
|
||||||
|
lineNumber++;
|
||||||
|
if (line.isBlank() || line.trim().startsWith("//"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.startsWith(":"))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nodeLines.add(line);
|
||||||
|
lineMap.add(lineNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parseNodes(nodeLines.toArray(String[]::new), lineMap.stream().mapToInt(i -> i).toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal recursiveAchievedPoints(LinkedHashSet<Node> nodes, MathContext mc)
|
||||||
|
{
|
||||||
|
var bd = BigDecimal.ZERO;
|
||||||
|
for (Node n : nodes)
|
||||||
|
{
|
||||||
|
bd = bd.add(n.achievedPoints(mc), mc);
|
||||||
|
bd = bd.add(recursiveAchievedPoints(n.getSubNodes(), mc), mc);
|
||||||
|
}
|
||||||
|
return bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal recursiveMaxPoints(LinkedHashSet<Node> nodes, MathContext mc)
|
||||||
|
{
|
||||||
|
var bd = BigDecimal.ZERO;
|
||||||
|
for (Node n : nodes)
|
||||||
|
{
|
||||||
|
bd = bd.add(n.maximumPoints(), mc);
|
||||||
|
bd = bd.add(recursiveMaxPoints(n.getSubNodes(), mc), mc);
|
||||||
|
}
|
||||||
|
return bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void recursiveToHtml(LinkedHashSet<Node> nodes, StringBuilder sb, HtmlContext hc, int depth)
|
||||||
|
{
|
||||||
|
for (Node n : nodes)
|
||||||
|
{
|
||||||
|
if (n.isVisibleInResultHtml())
|
||||||
|
{
|
||||||
|
sb.append(indent(depth));
|
||||||
|
sb.append(n.toResultHtml(hc).replace("\n", "\n" + indent(depth)));
|
||||||
|
sb.append("\n");
|
||||||
|
if (n.getSubNodes().stream().anyMatch(Node::isVisibleInResultHtml))
|
||||||
|
{
|
||||||
|
sb.append(indent(depth));
|
||||||
|
sb.append("<ul>\n");
|
||||||
|
recursiveToHtml(n.getSubNodes(), sb, hc, depth + 1);
|
||||||
|
sb.append(indent(depth));
|
||||||
|
sb.append("</ul>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
sb.append("\n<p>").append(recursiveAchievedPoints(nodes, hc.mc)).append("/")
|
||||||
|
.append(recursiveMaxPoints(nodes, hc.mc)).append("</p>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.awt.Component;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Pingger
|
* @author Pingger
|
||||||
|
@ -16,6 +17,11 @@ public interface Node
|
||||||
*/
|
*/
|
||||||
BigDecimal achievedPoints(MathContext mc);
|
BigDecimal achievedPoints(MathContext mc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param c the Change-Listener to add
|
||||||
|
*/
|
||||||
|
void addChangeListener(Consumer<Node> c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a Sub-Node to this Node
|
* Adds a Sub-Node to this Node
|
||||||
*
|
*
|
||||||
|
@ -43,11 +49,24 @@ public interface Node
|
||||||
*/
|
*/
|
||||||
BigDecimal maximumPoints();
|
BigDecimal maximumPoints();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired when a node changes
|
||||||
|
*
|
||||||
|
* @param n the specific Node the change originated
|
||||||
|
*/
|
||||||
|
void onChange(Node n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets this Element and all sub-elements to their defaults
|
* Resets this Element and all sub-elements to their defaults
|
||||||
*/
|
*/
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param n the parent node to set
|
||||||
|
* @throws IllegalStateException if a parent has already been set
|
||||||
|
*/
|
||||||
|
void setParentNode(Node n) throws IllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return this Node as a Config-String (with which this Node can be correctly
|
* @return this Node as a Config-String (with which this Node can be correctly
|
||||||
* parsed again using the Constructor)
|
* parsed again using the Constructor)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
package de.tuDortmund.cs.rvs.pingger.korrekturHelper;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
|
||||||
|
@ -27,6 +28,8 @@ public class RadioMultiSelect extends AbstractNode
|
||||||
public RadioMultiSelect(String config)
|
public RadioMultiSelect(String config)
|
||||||
{
|
{
|
||||||
var lines = config.split("\n");
|
var lines = config.split("\n");
|
||||||
|
if (lines.length <= 1)
|
||||||
|
{ throw new IllegalArgumentException("Not enough lines!"); }
|
||||||
var spl0 = lines[0].split("\t");
|
var spl0 = lines[0].split("\t");
|
||||||
if (!"\\\\".equals(spl0[0]))
|
if (!"\\\\".equals(spl0[0]))
|
||||||
{ throw new IllegalArgumentException("Expected \\\\"); }
|
{ throw new IllegalArgumentException("Expected \\\\"); }
|
||||||
|
@ -45,14 +48,17 @@ public class RadioMultiSelect extends AbstractNode
|
||||||
{
|
{
|
||||||
content.add(new JLabel(baseMsg));
|
content.add(new JLabel(baseMsg));
|
||||||
}
|
}
|
||||||
|
ActionListener cl = e -> onChange(this);
|
||||||
for (var i = 1; i < lines.length; i++)
|
for (var i = 1; i < lines.length; i++)
|
||||||
{
|
{
|
||||||
var s = lines[i].split("\t");
|
var s = lines[i].substring(1).split("\t");
|
||||||
if (s.length != 2)
|
if (s.length != 2)
|
||||||
{ throw new IllegalArgumentException("Expected exactly 1 \\t"); }
|
{ throw new IllegalArgumentException("Expected exactly 1 \\t"); }
|
||||||
|
System.out.println(s[0] + "\t" + s[1]);
|
||||||
points[i - 1] = new BigDecimal(s[0]);
|
points[i - 1] = new BigDecimal(s[0]);
|
||||||
text[i - 1] = s[1];
|
text[i - 1] = s[1];
|
||||||
rbs[i - 1] = new JRadioButton(text[i - 1]);
|
rbs[i - 1] = new JRadioButton(Utils.ptsToString(points[i - 1]) + "P - " + text[i - 1]);
|
||||||
|
rbs[i - 1].addActionListener(cl);
|
||||||
content.add(rbs[i - 1]);
|
content.add(rbs[i - 1]);
|
||||||
bg.add(rbs[i - 1]);
|
bg.add(rbs[i - 1]);
|
||||||
}
|
}
|
||||||
|
@ -115,8 +121,8 @@ public class RadioMultiSelect extends AbstractNode
|
||||||
public String toResultHtml(HtmlContext hc)
|
public String toResultHtml(HtmlContext hc)
|
||||||
{
|
{
|
||||||
return "<li" + hc.styleText(achievedPoints(hc.mc), maxPoints) + ">" + //
|
return "<li" + hc.styleText(achievedPoints(hc.mc), maxPoints) + ">" + //
|
||||||
"<span" + hc.stylePts(achievedPoints(hc.mc), maxPoints) + ">" + //
|
"<span" + hc.stylePts(achievedPoints(hc.mc), maxPoints) + "> " + //
|
||||||
achievedPoints(hc.mc) + "/" + maxPoints.toPlainString() + "P</span>" + //
|
achievedPoints(hc.mc) + " / " + maxPoints.toPlainString() + "P</span> " + //
|
||||||
(baseMsg == null ? text[getSelected()] : baseMsg + " (" + text[getSelected()] + ")") + "</li>";
|
(baseMsg == null ? text[getSelected()] : baseMsg + " (" + text[getSelected()] + ")") + "</li>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
// partial -> alle verbleibenden Fälle. Sonderfall: Elemente die 0 Punkte bringen (egal was ausgewählt ist) haben auch diesen Fall!
|
// partial -> alle verbleibenden Fälle. Sonderfall: Elemente die 0 Punkte bringen (egal was ausgewählt ist) haben auch diesen Fall!
|
||||||
:partialPts color: #fb0;
|
:partialPts color: #fb0;
|
||||||
:partialPtsText
|
:partialPtsText
|
||||||
|
:cbmsOk color: #080;
|
||||||
|
:cbmsFail color: #800;
|
||||||
!header # Test-Schema
|
!header # Test-Schema
|
||||||
[] -0.5 Punktabzug
|
[] -0.5 Punktabzug
|
||||||
[] +0.5 Bonus-Punkt
|
[] +0.5 Bonus-Punkt
|
||||||
!header ## Sub-Header zum versteck-Test
|
!header ## Sub-Header zum versteck-Test
|
||||||
[] -0.5 Punktabzug (uncheck um Sub-Header zu verstecken)
|
[] -0.5 Punktabzug (uncheck um Sub-Header zu verstecken)
|
||||||
!header ## Sub-Header für Punkte
|
!header ## Sub-Header für Punkte
|
||||||
\ 1.0 Element existiert | Element existiert nicht
|
\ 1.0 Element existiert | Element existiert nicht
|
||||||
|
@ -30,10 +32,12 @@
|
||||||
5.0 Volle Punkte
|
5.0 Volle Punkte
|
||||||
2.5 Halbe Punkte
|
2.5 Halbe Punkte
|
||||||
0 Null Punkte
|
0 Null Punkte
|
||||||
\\ 5.0 Text der immer angezeigt wird. Dadurch wird der Text bei den Punkten zur Begründung (Multi-Select anstatt Radio-Box. das kann nicht gemischt werden!)
|
\\ 5.0 Checkbox-Multiselect "basis"-Text wird immer benötigt (Multi-Select anstatt Radio-Box. das kann nicht gemischt werden!)
|
||||||
[] 1.0 Ziel 1
|
[] 1.0 Ziel 1
|
||||||
[] 1.0 Ziel 2
|
[] 1.0 Ziel 2
|
||||||
[] 2.0 Ziel 3
|
[] 2.0 Ziel 3
|
||||||
[] 0.5 Ziel 4
|
[] 0.5 Ziel 4
|
||||||
[] 0.5 Ziel 5
|
[] 0.5 Ziel 5
|
||||||
// Zeilenumbruch am Ende der Datei wichtig!
|
!header # Backdrop
|
||||||
|
[] -0.5 Entry
|
||||||
|
|
||||||
|
|
Reference in New Issue