The complete source code of the java applet

package net.mumie.mathlet;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.mumie.mathletfactory.action.updater.DependencyAdapter;
import net.mumie.mathletfactory.action.updater.DependencyUpdater;
import net.mumie.mathletfactory.appletskeleton.NoCanvasApplet;
import net.mumie.mathletfactory.appletskeleton.util.ControlPanel;
import net.mumie.mathletfactory.display.LineDisplayProperties;
import net.mumie.mathletfactory.display.g2d.MMG2DCanvas;
import net.mumie.mathletfactory.display.noc.number.MMDoubleSliderPanel;
import net.mumie.mathletfactory.math.number.MDouble;
import net.mumie.mathletfactory.math.number.MInteger;
import net.mumie.mathletfactory.mmobject.MMCanvasObjectIF;
import net.mumie.mathletfactory.mmobject.analysis.function.MMFunctionDefByOp;
import net.mumie.mathletfactory.mmobject.geom.affine.MMAffine2DLineSegment;
import net.mumie.mathletfactory.mmobject.geom.affine.MMAffine2DPoint;
import net.mumie.mathletfactory.mmobject.geom.affine.MMCoordinateSystem;
import net.mumie.mathletfactory.mmobject.number.MMDouble;
import net.mumie.mathletfactory.mmobject.number.MMInteger;
import net.mumie.mathletfactory.mmobject.number.MMOpNumber;
import net.mumie.mathletfactory.util.exercise.MultipleTasksIF;
import net.mumie.mathletfactory.util.exercise.MumieExercise;

/**
 * No description
 * 
 * @author unknown
 * @mm.type applet
 * @mm.section content/s3m2/sample/media/applets
 * @mm.copyright no copyright
 * @mm.requireJar system/libraries/jar_mathletfactory_base.meta.xml
 * @mm.requireJar system/libraries/jar_mathletfactory_graphics2d.meta.xml
 * @mm.docstatus
 * @mm.status devel_ok
 * @mm.description No description
 * @mm.rating none
 * @mm.changelog
 * @mm.width 500
 * @mm.height 500
 */
public class QuadraticFunctions extends NoCanvasApplet implements
    MultipleTasksIF {

  private static final Class NUMBER_CLASS = MDouble.class;

  private JComponent demo, training, problem;

  public void init() {
    try {
      super.init();
      setTitle(getMessage("applet.title"));
      demo = new DemoPanel();
      getCenterTabbedPanel().addTab(getMessage("applet.demo"), demo);
      training = new TrainPanel();
      getCenterTabbedPanel().addTab(getMessage("applet.training"), training);
      if (isHomeworkMode()) {
        problem = new ProblemPanel(this);
        getCenterTabbedPanel().addTab(getMessage("applet.problem"), problem);
      }
      getCenterTabbedPanel().remove(0);
      addDynamicResetButton();
    } catch (Throwable t) {
      reportError(t);
    }
  }

  class DemoPanel extends JPanel {
    // parameter objects
    String functionString;
    String varName;
    // other objects
    MMG2DCanvas canvas;
    MMCoordinateSystem cs;
    MMFunctionDefByOp function;
    MMAffine2DPoint xPoint;
    MMAffine2DLineSegment line;
    ControlPanel control;
    MMDouble x;
    MMDouble y;
    MMDoubleSliderPanel xSlider;

    public DemoPanel() {
      super(new BorderLayout());

      // getParameters
      getParams();

      // create canvas objects
      canvas = new MMG2DCanvas();
      cs = new MMCoordinateSystem();
      cs.setXAxisLabel(varName); // sets the label of the x-axis from the default ("x") to varName
      function = new MMFunctionDefByOp(NUMBER_CLASS, functionString);
      function.setVariableId(varName);
      xPoint = new MMAffine2DPoint(NUMBER_CLASS, 0, 0);// creates a point at (0,0)
      double yValue = function.evaluate(0);// evaluate the function for x=0
      line = new MMAffine2DLineSegment(NUMBER_CLASS, 0, 0, 0, yValue);// creates a line segment between (0,0) and (0,yValue)
      // create control objects
      control = new ControlPanel();
      x = new MMDouble(0); // start value: x = 0
      x.setLabel(varName + " = ");// set the label which will be displayed when this object is added to a container
      y = new MMDouble(yValue);
      xSlider = x.getAsSlider();// get the slider representation of x, everytime the slider is moved, the x value will be updated.
      xSlider.setLeftBound(-5);// set the left bound (minimum) of the slider
      xSlider.setRightBound(5);// set the right bound (maximum) of the slider

      // set display properties
      function.setColor(Color.green.darker());// set the color of the function to dark green
      function.getDisplayProperties().setBorderWidth(2);// border width = 2px.
      xPoint.setColor(Color.orange);// point color = orange
      xPoint.setBorderColor(Color.black);// point border-color = black
      line.setColor(Color.blue);
      ((LineDisplayProperties) line.getDisplayProperties()).setLineWidth(0.1);

      // add objects to canvas
      canvas.addObject(cs);
      canvas.addObject(function);
      canvas.addObject(xPoint);
      canvas.addObject(line);
      // set the default scene
      canvas.getW2STransformationHandler().setUniformWorldDim(10);

      // add objects to controlPanel
      control.add(function.getAsContainerContent());// gets the UI Component of the function and add it to the ControlPanel
      control.insertLineBreak();// ends the current line
      control.add(xSlider);// xSlider is already a JComponent
      control.insertLineBreak();
      control.addText("f (");// add a text to the current line
      control.add(x.getAsContainerContent());
      control.addText(") = ");
      control.add(y.getAsContainerContent());

      // add the canvas and control Panel
      add(canvas, BorderLayout.CENTER);// add the canvas to the center
      add(control, BorderLayout.SOUTH);// add the canvas to the south

      defineDependencies();
    }

    public void defineDependencies() {
      DependencyAdapter adapter = new DependencyAdapter() {
        public void doUpdate() {// this method will be executed when x is updated
          double xValue = x.getDouble(); // get the currect x value
          double yValue = function.evaluate(xValue);// calculate the y value
          y.setDouble(yValue);// set the value to y
          y.render();// call render to repaint the UI-Component

          xPoint.setX(xValue);// update the x coordinate of xPoint
          xPoint.render();// call render to refresh the point

          line.setInitialPoint(xPoint);// update the initial point
          line.setEndPoint(xValue, yValue);// update the end point
          line.render();

          canvas.repaint();// repaint the canvas
        }
      };

      y.dependsOn(x, adapter);// now everytime x is updated the adapter's doUpdate will be executed.
    }

    public void getParams() {
      functionString = getParameter("demoFunction", "x|_.2+2x+1");
      varName = getParameter("varName", "x");
    }

    public void reset() {
      x.setDouble(0);// set x to 0
      x.render();// refresh
      DependencyUpdater.performActionCycleFromObject(x);// update all objects depending on x
      canvas.getW2STransformationHandler().setUniformWorldDim(10);// reset the scene of the canvas
      canvas.renderScene();// render the scene
      canvas.repaint();// repaint
    }
  }

  class TrainPanel extends JPanel {
    private static final String CORRECT = "<html><font color=green><b>\u2713</b></font></html>";// unicode for check mark
    private static final String FALSE = "<html><font color=red><b>\u0192</b></font></html>";// unicode for false mark
    // task parameter f(x) = x|_.2 + b + c
    int x1, x2, b, c;// x1 and x2 are the roots, b and c will be calculated
    MMDouble d; // x for task b

    MMG2DCanvas canvas;
    MMFunctionDefByOp function;
    MMCoordinateSystem cs;

    ControlPanel control;// the outer control panel
    ControlPanel taskPanel;// the task panel
    ControlPanel root2Panel;// wrapper for the root2 textfield
    JComboBox numberOfRoots;// drop down list
    MMDouble root1, root2;// real numbers for root1 and root2
    MMDouble answer;// real number for the answer of subtask b

    JButton check, newTask;// buttons for check
    JLabel label1, label2;// correction label for task a and task b.

    public TrainPanel() {
      super(new BorderLayout());

      // init canvas objects
      canvas = new MMG2DCanvas();
      cs = new MMCoordinateSystem();
      function = new MMFunctionDefByOp(NUMBER_CLASS, "x");

      // init control panel objects
      d = new MMDouble(0);
      label1 = new JLabel();
      label2 = new JLabel();
      root1 = new MMDouble();
      root1.setEditable(true);// set as editable
      root1.setEdited(false);
      // The input fields should be at the unedited state, a red question mark will be displayed
      // We repeat this for the other number fields
      root2 = new MMDouble();
      root2.setEditable(true);
      root2.setEdited(false);
      answer = new MMDouble();
      answer.setEditable(true);
      answer.setEdited(false);

      control = new ControlPanel();
      taskPanel = new ControlPanel();
      // root2Panel is a wrapper for root2 which will only be visible if the user select 2 as number of roots
      root2Panel = new ControlPanel();
      root2Panel.addText(",");// add the "," text because the roots will be displayed as a set
      root2Panel.add(root2.getAsContainerContent());// add root2
      root2Panel.setVisible(false);// at the beginning root2Panel is hidden

      String[] entries = new String[] { "1", "2" };// entries for the drop down list
      numberOfRoots = new JComboBox(entries);
      numberOfRoots.setSelectedIndex(0);// at the beginning, selected index = 0

      check = new JButton("Check");// Button for checking the result
      newTask = new JButton("New Task");// Button for generating new task

      getNewTask(true);

      // adding action listeners
      check.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          check();// call the check method
        }
      });
      newTask.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          getNewTask(false);// generate new task
        }
      });

      numberOfRoots.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          if (numberOfRoots.getSelectedIndex() == 0) {
            root2Panel.setVisible(false); // only one root, hide root2Panel
          } else {
            root2Panel.setVisible(true);// show root2Panel
          }
        }
      });

      // add objects to the canvas
      canvas.addObject(cs);
      canvas.addObject(function);
      canvas.getW2STransformationHandler().setUniformWorldDim(10);

      taskPanel.setBorder(BorderFactory.createLineBorder(Color.black));
      taskPanel.setLeftAlignment();
      taskPanel.addText("\\textbf{a). }");
      taskPanel.addText("Find all real roots of f(x)!");
      taskPanel.insertLineBreak();
      taskPanel.insertTab();
      taskPanel.addText("Numbers of roots of f(x) = ");
      taskPanel.add(numberOfRoots);
      taskPanel.insertLineBreak();
      taskPanel.insertTab();
      taskPanel.addText("The root(s) of f(x) = ");
      taskPanel.addText("{");
      taskPanel.add(root1.getAsContainerContent());
      taskPanel.add(root2Panel);
      taskPanel.addText("}");
      taskPanel.add(label1);
      taskPanel.insertLineBreaks(2);
      taskPanel.addText("\\textbf{b). }");
      taskPanel.addText("f (");
      taskPanel.add(d.getAsContainerContent());
      taskPanel.addText(") = }");
      taskPanel.add(answer.getAsContainerContent());
      taskPanel.add(label2);

      control.addText("Consider the function: ");
      control.add(function.getAsContainerContent());
      control.insertLineBreaks(2);
      control.add(taskPanel);
      control.insertLineBreaks(2);
      control.add(check);
      control.insertTab();
      control.add(newTask);

      add(canvas, BorderLayout.CENTER);
      add(control, BorderLayout.SOUTH);

    }

    private void check() {
      // task a
      boolean correct = false;// answer is correct?
      boolean x1Correct = false;// x1 is in answer?
      boolean x2Correct = false;// x2 is in answer?
      boolean isEdited = false;// are the answers edited?
      if (x1 != x2) {// 2 different roots were generated
        isEdited = root1.isEdited() && root2.isEdited(); // check if both roots are edited
        x1Correct = equalCheck(x1, root1.getDouble())
            || equalCheck(x1, root2.getDouble());
        x2Correct = equalCheck(x2, root1.getDouble())
            || equalCheck(x2, root2.getDouble());
        correct = isEdited && x1Correct && x2Correct;// only correct if both roots are edited and both x1 and x2 are found in the answer
      } else {
        correct = x1 == root1.getDouble() && root1.isEdited();// correct if root1 is edited and root1 equals x1
      }
      if (correct) {
        label1.setText(CORRECT);// set the label to correct
      } else {
        label1.setText(FALSE);// set the label to false
      }

      // Task b
      double expected = function.evaluate(d.getDouble());// the expected solution
      boolean correct2 = equalCheck(expected, answer.getDouble())
          && answer.isEdited();
      if (correct2) {
        label2.setText(CORRECT);
      } else {
        label2.setText(FALSE);
      }
    }

    /**
     * checks whether or not two real numbers are equal with 0.005 precision
     * 
     * @return true if |a-b| < 0.005
     */
    private boolean equalCheck(double a, double b) {
      return Math.abs(a - b) < 0.005; // check with 0.005 precision
    }

    private void getNewTask(boolean defaultTask) {
      label1.setText(""); // reset the correction label for task a
      label2.setText(""); // reset the correction label for task b
      if (defaultTask) {
        // set the roots for the default task here
        x1 = -2;
        x2 = 3;
      } else {
        // otherwise select the roots randomly
        x1 = -5 + (int) (Math.random() * 11); // x1 \in [-5,5]
        x2 = -5 + (int) (Math.random() * 11); // x1 \in [-5,5]
      }
      // f(x) = (x-x1)*(x-x2) = x|_.2 - (x1+x2)*x + x1*x2
      b = -(x1 + x2); // calculate b
      c = x1 * x2;// calculate c

      // Generate value for d, make sure d is not one of the roots
      double dValue = x1;
      if (dValue == x1 || dValue == x2) {
        dValue = -5 + (int) (Math.random() * 11);
      }
      d.setDouble(dValue);
      d.render();
      function.setOperation("x|_.2+" + b + "x+" + c);// set the operation as f(x) = x|_.2+bx+c
      function.render();
      canvas.repaint();
    }

    public void reset() {
      getNewTask(true); // Get the default task
      canvas.getW2STransformationHandler().setUniformWorldDim(10);// reset canvas scene
      canvas.renderScene();
      canvas.repaint();
    }
  }

  class ProblemPanel extends ControlPanel {
    private MumieExercise mumieExercise;
    private final String[] subtaskLabel = new String[] { "a", "b" };// adjust if necessary
    private final int subtaskCount = 2;// adjust if necessary
    private int currentSubTaskNr = 1;
    private ControlPanel[] subtasks = new ControlPanel[subtaskCount];
    // end of generated variables
    private MMOpNumber polynomial;// to display the function
    private MMInteger d;// the x-Value for task b
    // user input
    // Task a
    JComboBox numberOfRoots;// drop down list
    MMDouble root1, root2;// real number editable fields for the root(s)
    ControlPanel root2Panel;// wrapper for root2
    // Task b
    MMDouble answer;// the answer field for task b

    public ProblemPanel(MultipleTasksIF exercise) {
      mumieExercise = new MumieExercise(exercise, subtaskCount);

      // load the problem from the datasheet
      polynomial = new MMOpNumber();
      mumieExercise.loadElement("user/problem/polynomial", polynomial);
      d = new MMInteger();
      mumieExercise.loadElement("user/problem/d", d);

      addText("Consider the function");
      insertLineBreak();
      addText("f(x) = ");
      add(polynomial.getAsContainerContent());
      insertLineBreaks(2);

      for (int i = 0; i < subtaskCount; i++) {
        subtasks[i] = new ControlPanel();
        subtasks[i].setBorder(BorderFactory
            .createTitledBorder(getMessage("applet.problem") + " " 
                + subtaskLabel[i] + ")"));// add a titled border to the subtasks
        add(subtasks[i]);// add the subtask to the ProblemPanel
        subtasks[i].setLeftAlignment();
      }

      // task1
      root1 = new MMDouble();
      root1.setEditable(true);
      root1.setEdited(false);

      root2 = new MMDouble();
      root2.setEditable(true);
      root2.setEdited(false);

      root2Panel = new ControlPanel();
      root2Panel.addText(",");
      root2Panel.add(root2.getAsContainerContent());
      root2Panel.setVisible(false);

      numberOfRoots = new JComboBox(new String[] { "1", "2" });
      numberOfRoots.setSelectedIndex(0);
      numberOfRoots.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          if (numberOfRoots.getSelectedIndex() == 0) {
            root2Panel.setVisible(false);
          } else {
            root2Panel.setVisible(true);
          }
        }
      });
      subtasks[0].addText(getMessage("applet.txt2"));
      subtasks[0].insertLineBreak();
      subtasks[0].addText(getMessage("applet.txt3"));
      subtasks[0].add(numberOfRoots);
      subtasks[0].insertLineBreak();
      subtasks[0].addText(getMessage("applet.txt4"));
      subtasks[0].addText("{");
      subtasks[0].add(root1.getAsContainerContent());
      subtasks[0].add(root2Panel);
      subtasks[0].addText("}");
      subtasks[0].insertTabs(3);// add some space to make the subtask panel wider
      // task2
      answer = new MMDouble();
      answer.setEditable(true);
      answer.setEdited(false);
      subtasks[1].addText("f(" + d.getIntValue() + ") = ");
      subtasks[1].add(answer.getAsContainerContent());
      subtasks[1].insertTabs(4);// add some space to make the subtask panel wider

      loadAnswers();// load existing answers
      // add content to the subtask problems here
      // use e.g.: subtasks[0].addControl(c), subtasks[0].addText(labelText), ...
      insertLineBreak();
      add(mumieExercise.getSendButton());// adds the save button to send the answers to the server
      selectTask(currentSubTaskNr);
    }

    public void loadAnswers() {
      // task a
      if (mumieExercise.userElementExists(1, "numOfRoots")) {// check if the answer exists
        MInteger temp = new MInteger();// temporary object for numOfRoots
        mumieExercise.loadUserElement(1, "numOfRoots", temp);
        numberOfRoots.setSelectedIndex(temp.getIntValue() - 1);
        mumieExercise.loadUserElement(1, "root1", root1);
        if (numOFRoots == 2) {// check if numOFRoots == 2
          mumieExercise.loadUserElement(1, "root2", root2);
          root2Panel.setVisible(true);// show the root2
        }
        root1.render();// refresh the input field
        root2.render();// refresh the input field
      }
      // task b
      if (mumieExercise.userElementExists(2, "answer")) {
        mumieExercise.loadUserElement(2, "answer", answer);
        answer.render();
      }
    }

    public boolean collectAnswers() {
      mumieExercise.setAnswer(1, "numOfRoots", new MInteger(numberOfRoots
          .getSelectedIndex() + 1));
      mumieExercise.setAnswer(1, "root1", root1);// save the first root
      if (numberOfRoots.getSelectedIndex() == 1) {
        mumieExercise.setAnswer(1, "root2", root2);// save the second root (if exists)
      }
      // task b
      mumieExercise.setAnswer(2, "answer", answer);
      return true;
    }

    public void selectTask(int taskNr) {
      currentSubTaskNr = taskNr;
      for (int i = 1; i <= subtaskCount; i++)
        if (i == currentSubTaskNr)
          subtasks[i - 1].setVisible(true);
        else
          subtasks[i - 1].setVisible(false);
    }

    public void reset() {
      if (currentSubTaskNr == 1) {
        root1.setEdited(false);
        root1.render();
        root2.setEdited(false);
        root2.render();
        numberOfRoots.setSelectedIndex(0);
        root2Panel.setVisible(false);
      }

      if (currentSubTaskNr == 2) {
        answer.setEdited(false);
        answer.render();
      }
    }
  }

  public void resetDemo() {
    ((DemoPanel) demo).reset();
  }

  public void resetTraining() {
    ((TrainPanel) training).reset();
  }

  public void reset() {

  }

  public void clearSubtask() {
    ((ProblemPanel) problem).reset();
  }

  public boolean collectAnswers() {
    return ((ProblemPanel) problem).collectAnswers();
  }

  public void selectTask(int taskNr) {
    ((ProblemPanel) problem).selectTask(taskNr);
  }

}

Add picture from clipboard (Maximum size: 500 MB)