Beispiel #1
0
  /**
   * @return Locale-specific sample input string which meets datatype criteria for node. Used for
   *     error reporting.
   */
  String getSampleInputString() {
    /* Create the help-string showing allowable range of input values.
    Can be re-created (e.g. if range dynamically changes */

    String min = null;
    String max = null;
    String other = null;
    String rangeStr = null;
    String s = null;

    s = Datum.getExampleFormatStr(triceps, mask, datumType);

    if (!(s == null || s.equals(""))) {
      rangeStr = " (e.g. " + s + ")";
    }

    if (answerType == PASSWORD) {
      return "";
    }
    if (minDatum == null
        && maxDatum == null
        && allowableDatumValues == null
        && pattern == null
        && rangeStr != null) {
      return rangeStr;
    }

    if (minDatum != null) {
      setMinDatum(minDatum);
      min = minDatum.stringVal(true, mask);
    }
    if (maxDatum != null) {
      setMaxDatum(maxDatum);
      max = maxDatum.stringVal(true, mask);
    }
    if (allowableDatumValues != null) {
      other = buildOrList(allowableDatumValues);
    }

    if (minDatum != null && maxDatum != null) {
      if ((new DatumMath()).lt(maxDatum, minDatum).booleanVal()) {
        setError(triceps.get("max_less_than_min") + "(" + minStr + " - " + maxStr + ")");
      }
    }

    rangeStr = "(" + ((min != null) ? min : "") + " - " + ((max != null) ? max : "") + ")";
    if (other != null) {
      rangeStr = " [" + rangeStr + other + "]";
    }
    if (pattern != null) {
      rangeStr = "(e.g. m/" + pattern + "/";
    }

    if (!rangeStr.equals("( - )")) {
      return " " + rangeStr;
    }
    return "";
  }
Beispiel #2
0
  /**
   * Helper function to build OR list of data values
   *
   * @param v vector of Nodes
   */
  private String buildOrList(Vector v) {
    StringBuffer sb = new StringBuffer();

    for (int i = 0; i < v.size(); ++i) {
      Datum d = (Datum) v.elementAt(i);
      sb.append("," + ((i == v.size() - 1) ? (" " + triceps.get("or")) : "") + " " + d.stringVal());
    }
    return sb.toString();
  }
Beispiel #3
0
  /** @return false if the selected value violates the validation criteria */
  boolean isWithinRange(Datum d) {
    boolean err = false;

    if (minDatum != null) {
      if (!(new DatumMath()).ge(d, minDatum).booleanVal()) {
        err = true;
      }
    }
    if (maxDatum != null) {
      if (!(new DatumMath()).le(d, maxDatum).booleanVal()) {
        err = true;
      }
    }
    if (err && allowableDatumValues != null) {
      /* then not within valid range - so check if it is an outlying, but allowable value */
      for (int i = 0; i < allowableDatumValues.size(); ++i) {
        if ((new DatumMath()).eq(d, (Datum) allowableDatumValues.elementAt(i)).booleanVal()) {
          err = false;
          break;
        }
      }
    }
    if (pattern != null) {
      if (!Pattern.matches(pattern, d.stringVal())) {
        err = true;
      }
    }

    if (err) {
      if (answerType == PASSWORD) {
        setError(triceps.get("incorrect_password"));
      } else {
        setError(
            triceps.get("please_enter_a")
                + Datum.getTypeName(triceps, datumType)
                + triceps.get("in_the_range")
                + getSampleInputString());
      }
    }
    return !(err);
  }
Beispiel #4
0
  /**
   * Create HTML input field for this node, given its currently selected value and possible error
   * messages
   *
   * @param datum the value
   * @param errMsg optional error messages
   * @param autogen whether to auto-number the options
   * @return HTML fragment
   */
  String prepareChoicesAsHTML(Datum datum, String errMsg, boolean autogen) {
    /* errMsg is a hack - only applies to RADIO_HORIZONTAL */
    StringBuffer sb = new StringBuffer();
    String defaultValue = "";
    AnswerChoice ac;
    Enumeration ans = null;
    Vector v = null;

    switch (answerType) {
      case RADIO: // will store integers
        ans = getAnswerChoices().elements();
        while (ans.hasMoreElements()) { // for however many radio buttons there are
          ac = (AnswerChoice) ans.nextElement();
          ac.parse(triceps);
          sb.append(
              "<input type='radio' name='"
                  + getLocalName()
                  + "' id ='"
                  + getLocalName()
                  + "' value='"
                  + ac.getValue()
                  + "'"
                  + (isSelected(datum, ac) ? " checked " : " ")
                  + ">"
                  + ac.getMessage()
                  + "<br>");
        }
        break;
      case RADIO_HORIZONTAL:
        { // will store integers
          /* table underneath questions */
          v = getAnswerChoices();
          ans = v.elements();
          int count = v.size();

          if (count > 0) {
            Double pct = new Double(100. / (double) count);
            sb.append("<table cellpadding='0' cellspacing='1' border='1' width='100%'>");
            sb.append("<tr>");
            while (ans.hasMoreElements()) { // for however many radio buttons there are
              ac = (AnswerChoice) ans.nextElement();
              ac.parse(triceps);
              sb.append("<td valign='top' width='" + pct.toString() + "%'>");
              sb.append(
                  "<input type='radio' name='"
                      + getLocalName()
                      + "' id='"
                      + getLocalName()
                      + "' value='"
                      + ac.getValue()
                      + "'"
                      + (isSelected(datum, ac) ? " checked " : " ")
                      + ">"
                      + ac.getMessage());
              sb.append("</td>");
            }
            sb.append("</tr>");
            sb.append("</table>");
          }
        }
        break;
      case RADIO_HORIZONTAL2:
        {
          /* table underneath questions */
          v = getAnswerChoices();
          ans = v.elements();
          int count = v.size();
          int max_width =
              Integer.parseInt(
                  triceps.getSchedule().getReserved(Schedule.ANSWER_OPTION_FIELD_WIDTH));

          if (count > 0) {
            Double pct = new Double((double) max_width / (double) count);
            sb.append(
                "<table cellpadding='0' cellspacing='1' border='1' width='100%'>"); // oddly, 100%
            // means all of
            // the enclosing
            // <td>, but for
            // embedded
            // <td>s, need
            // actual
            // percent of
            // top-level
            // table!
            sb.append("<tr>");
            while (ans.hasMoreElements()) { // for however many radio buttons there are
              ac = (AnswerChoice) ans.nextElement();
              ac.parse(triceps);
              sb.append("<td valign='top' width='" + pct.toString() + "%'>");
              sb.append(
                  "<input type='radio' name='"
                      + getLocalName()
                      + "' id='"
                      + getLocalName()
                      + "' value='"
                      + ac.getValue()
                      + "'"
                      + (isSelected(datum, ac) ? " checked " : " ")
                      + ">"
                      + ac.getMessage());
              sb.append("</td>");
            }
            sb.append("</tr>");
            sb.append("</table>");
          }
        }
        break;
      case CHECK:
        ans = getAnswerChoices().elements();
        while (ans.hasMoreElements()) { // for however many radio buttons there are
          ac = (AnswerChoice) ans.nextElement();
          ac.parse(triceps);
          sb.append(
              "<input type='checkbox' name='"
                  + getLocalName()
                  + "' id='"
                  + getLocalName()
                  + "' value='"
                  + ac.getValue()
                  + "'"
                  + (isSelected(datum, ac) ? " checked " : " ")
                  + ">"
                  + ac.getMessage()
                  + "<br>");
        }
        break;
      case COMBO: // stores integers as value
      case COMBO2:
      case LIST2:
      case LIST:
        {
          StringBuffer choices = new StringBuffer();
          ans = getAnswerChoices().elements();

          int optionNum = 0;
          int totalLines = 0;
          boolean nothingSelected = true;
          while (ans.hasMoreElements()) { // for however many radio buttons there are
            ac = (AnswerChoice) ans.nextElement();
            ac.parse(triceps);
            ++optionNum;

            String messageStr = ac.getMessage();
            String prefix = "<option value='" + ac.getValue() + "'";
            boolean selected = isSelected(datum, ac);
            if (selected) {
              nothingSelected = false;
            }

            int max_text_len =
                Integer.parseInt(
                    triceps.getSchedule().getReserved(Schedule.MAX_TEXT_LEN_FOR_COMBO));

            v = subdivideMessage(messageStr, max_text_len);

            for (int i = 0; i < v.size(); ++i) {
              choices.append(prefix);
              if (i == 0 && selected) {
                choices.append(" selected");
              }
              choices.append(">");
              if (i == 0) { // show selection number
                if (answerType == COMBO || answerType == LIST) {
                  choices.append((autogen) ? String.valueOf(optionNum) : ac.getValue());
                  choices.append(")&nbsp;");
                }
              } else { // indent to indicate that same as previous
                choices.append("&nbsp;&nbsp;&nbsp;");
              }
              choices.append((String) v.elementAt(i));
              choices.append("</option>");
            }
            totalLines += v.size();
          }
          sb.append(
              "<select name='"
                  + getLocalName()
                  + "' id='"
                  + getLocalName()
                  + "' "
                  + ((answerType == LIST || answerType == LIST2)
                      ? (" size = '" + Math.min(MAX_ITEMS_IN_LIST, totalLines + 1) + "' ")
                      : " ")
                  + ">");
          sb.append(
              "<option value=''"
                  + ((nothingSelected) ? " selected" : "")
                  + ">"
                  + // so that focus is properly shifted on List box
                  triceps.get("select_one_of_the_following")
                  + "</option>"); // first choice is empty
          sb.append(choices);
          sb.append("</select>");
        }
        break;
      case TEXT: // stores Text type
        if (datum != null && datum.exists()) {
          defaultValue = datum.stringVal();
        }
        sb.append(
            "<input type='text' "
                + " name='"
                + getLocalName()
                + "' id='"
                + getLocalName()
                + "' value='"
                + (new XMLAttrEncoder()).encode(defaultValue)
                + "'>");
        break;
      case MEMO:
        if (datum != null && datum.exists()) {
          defaultValue = datum.stringVal();
        }
        sb.append(
            "<textarea rows='5'"
                + " name='"
                + getLocalName()
                + "' id='"
                + getLocalName()
                + "'>"
                + (new XMLAttrEncoder()).encode(defaultValue)
                + "</textarea>");
        break;
      case PASSWORD: // stores Text type
        if (datum != null && datum.exists()) {
          defaultValue = datum.stringVal();
        }
        sb.append(
            "<input type='password'"
                + " name='"
                + getLocalName()
                + "' id='"
                + getLocalName()
                + "' value='"
                + (new XMLAttrEncoder()).encode(defaultValue)
                + "'>");
        break;
      case DOUBLE: // stores Double type
        if (datum != null && datum.exists()) {
          defaultValue = datum.stringVal();
        }
        sb.append(
            "<input type='text'"
                + " name='"
                + getLocalName()
                + "' id='"
                + getLocalName()
                + "' value='"
                + defaultValue
                + "'>");
        break;
      default:
        /*
        case DATE:
        case TIME:
        case YEAR:
        case MONTH:
        case DAY:
        case WEEKDAY:
        case HOUR:
        case MINUTE:
        case SECOND:
        case MONTH_NUM:
        case DAY_NUM:
         */
        if (datum != null && datum.exists()) {
          defaultValue = datum.stringVal();
        }
        sb.append(
            "<input type='text'"
                + " name='"
                + getLocalName()
                + "' id='"
                + getLocalName()
                + "' value='"
                + defaultValue
                + "'>");
        break;
      case NOTHING:
        sb.append("&nbsp;");
        break;
    }

    return sb.toString();
  }
Beispiel #5
0
  /**
   * Helper function to parse Answer Options and populate Node object
   *
   * @param langNum which language vector to populate
   * @param src The string to be parsed
   * @return true if suceeds
   */
  private boolean parseAnswerOptions(int langNum, String src) {
    /* Need to make sure that the answer type, order of answers, and internal values of answers are the same across all languages */
    if (src == null) {
      if (AUTHORABLE) {
        setParseError(triceps.get("answerOptions_column_missing"));
      } else {
        setParseError("syntax error");
      }
      return false;
    }

    StringTokenizer ans = new StringTokenizer(src, "|", true); // return '|' tokens too
    String token = "";

    // Determine the question type (first token)
    try {
      token = ans.nextToken();
    } catch (NoSuchElementException t) {
      Logger.getLogger(LoggerName).log(Level.SEVERE, "missing_display_type", t);
      if (AUTHORABLE) {
        setParseError(triceps.get("missing_display_type") + t.getMessage());
      } else {
        setParseError("syntax error");
      }
    }

    if (langNum == 0) {
      for (int z = 0; z < QUESTION_TYPES.length; ++z) {
        if (token.equalsIgnoreCase(QUESTION_TYPES[z])) {
          answerType = z;
          break;
        }
      }
    } else {
      if (!QUESTION_TYPES[answerType].equalsIgnoreCase(token)) {
        if (AUTHORABLE) {
          setParseError(triceps.get("mismatch_across_languages_in_answerType"));
        } else {
          setParseError("syntax error");
        }
      }
      // don't change the known value for answerType
    }

    if (questionOrEvalType == EVAL) {
      answerType = NOTHING; // so no further processing
    } else if (answerType == BADTYPE) {
      if (AUTHORABLE) {
        setParseError(triceps.get("invalid_answerType"));
      } else {
        setParseError("syntax error");
      }
      answerType = NOTHING;
    }

    if (datumType == Datum.INVALID) {
      /* so only if not set via datumTypeStr */
      datumType = DATA_TYPES[answerType];
    }

    switch (answerType) {
      case CHECK:
      case COMBO:
      case LIST:
      case RADIO:
      case RADIO_HORIZONTAL:
      case RADIO_HORIZONTAL2:
      case COMBO2:
      case LIST2:
        String val = null;
        String msg = null;
        int field = 0;
        Vector ansOptions = new Vector();
        Vector prevAnsOptions = null;

        if (langNum > 0) {
          prevAnsOptions = getValuesAt(answerChoicesVector, 0);
        }

        int ansPos = 0;

        while (ans.hasMoreTokens()) {
          String s = null;
          s = ans.nextToken();

          if ("|".equals(s)) {
            ++field;
            continue;
          }
          switch (field) {
            case 0:
              break; // discard the first token - answerType
            case 1:
              val = s;
              if (langNum > 0) {
                boolean err = false;
                String s2 = null; // previous answer
                try {
                  s2 = ((AnswerChoice) prevAnsOptions.elementAt(ansPos++)).getValue();
                  if (!s2.equals(val)) {
                    err = true;
                  }
                } catch (NullPointerException t) {
                  Logger.getLogger(LoggerName).log(Level.SEVERE, "", t);
                  err = true;
                } catch (ArrayIndexOutOfBoundsException t) {
                  Logger.getLogger(LoggerName).log(Level.SEVERE, "", t);
                  err = true;
                }
                if (err) {
                  if (AUTHORABLE) {
                    setParseError(
                        triceps.get(
                                "mismatch_across_languages_in_return_value_for_answerChoice_num")
                            + (ansPos - 1));
                  } else {
                    setParseError("syntax error");
                  }
                  val = s2; // reset it to the previously known return value for consistency (?)
                }
              }
              break;
            case 2:
              msg = s;
              field = 0; // so that cycle between val & msg;
              if (val == null || msg == null) {
                if (AUTHORABLE) {
                  setParseError(
                      triceps.get("missing_value_or_message_for_answerChoice_num") + (ansPos - 1));
                } else {
                  setParseError("syntax error");
                }
              } else {
                AnswerChoice ac = new AnswerChoice(val, msg);
                ansOptions.addElement(ac);

                /* check for duplicate answer choice values */
                if (langNum == 0) { // only for first pass
                  if (answerChoicesHash.put(val, ac) != null) {
                    if (AUTHORABLE) {
                      setParseError(triceps.get("answerChoice_value_already_used") + val);
                    } else {
                      setParseError("syntax error");
                    }
                  }
                }
              }
              val = null;
              msg = null;
              break;
          }
        }
        if (ansOptions.size() == 0) {
          if (AUTHORABLE) {
            setParseError(triceps.get("answerChoices_must_be_specified"));
          } else {
            setParseError("syntax error");
          }
        }
        if (field == 1) {
          if (AUTHORABLE) {
            setParseError(triceps.get("missing_message_for_answerChoice_num") + (ansPos - 1));
          } else {
            setParseError("syntax error");
          }
        }
        if (langNum > 0) {
          if (prevAnsOptions.size() != ansOptions.size()) {
            if (AUTHORABLE) {
              setParseError(
                  triceps.get("mismatch_across_languages_in_number_of_answerChoices")
                      + prevAnsOptions.size()
                      + " != "
                      + ansOptions.size());
            } else {
              setParseError("syntax error");
            }
          }
        }
        answerChoicesVector.addElement(ansOptions);
        break;
      default:
        break;
    }

    return true;
  }
Beispiel #6
0
  /**
   * Helper function to parse the Question or Eval field, which also includes optional validation
   * criteria
   */
  private void parseQuestionOrEvalTypeField() {
    StringTokenizer ans;
    int z;

    if (questionOrEvalTypeField == null) {
      if (AUTHORABLE) {
        setParseError(triceps.get("questionOrEvalTypeField_must_exist"));
      } else {
        setParseError("syntax error");
      }
      return;
    }

    ans = new StringTokenizer(questionOrEvalTypeField, ";", true); // return ';' tokens too

    for (int field = 0; ans.hasMoreTokens(); ) {
      String s = null;
      s = ans.nextToken();

      if (";".equals(s)) {
        ++field;
        continue;
      }
      switch (field) {
        case 0:
          questionOrEvalTypeStr = s;
          for (z = 0; z < ACTION_TYPES.length; ++z) {
            if (questionOrEvalTypeStr.equalsIgnoreCase(ACTION_TYPES[z])) {
              questionOrEvalType = z;
              break;
            }
          }
          break;
        case 1:
          datumTypeStr = s;
          datumType = Datum.parseDatumType(s);
          if (datumType == -1) {
            if (AUTHORABLE) {
              setParseError(triceps.get("invalid_dataType") + datumTypeStr);
            } else {
              setParseError("syntax error");
            }
            datumType = Datum.INVALID;
          }
          break;
        case 2:
          minStr = s;
          break;
        case 3:
          maxStr = s;
          break;
        case 4:
          /* FIXME:  HACK -- does double duty -- either a formatting mask, OR a regex input mask */
          if (s == null || s.trim().length() == 0 || !s.startsWith("PERL5")) {
            mask = s;
            pattern = null;
          } else {
            pattern = s.substring("PERL5".length());
            try {
              Pattern.compile(pattern);
            } catch (PatternSyntaxException ex) {
              setParseError(
                  "Invalid Regular Expression Pattern " + pattern + " " + ex.getMessage());
            }
          }
          break;
        default:
          /* extra parameters are additional allowable values, as Strings that will be parsed */
          if (allowableValues == null) {
            allowableValues = new Vector();
          }
          allowableValues.addElement(s);
          break;
      }
    }
  }
Beispiel #7
0
  /**
   * Create a new Item - reading the contents from the tab separated value set of columns. Loads it
   * into the Node object
   *
   * @param lang the Triceps context
   * @param sourceLine the line number within the source file (for debugging purposes)
   * @param sourceFile the name of the source file (for debugging purposes)
   * @param tsv the tab separated list of colums representing the node contents
   * @param numLanguage to know how many langauges to parsse?
   */
  Node(Triceps lang, int sourceLine, String sourceFile, String tsv, int numLanguages) {
    triceps = /*(lang == null) ? new Triceps() :*/ lang;
    String token;
    int field = 0;

    if (numLanguages < 1) {
      if (AUTHORABLE) {
        setParseError(triceps.get("numLanguages_must_be_greater_than_zero") + numLanguages);
      } else {
        setParseError("syntax error");
      }
      numLanguages = 1; // the default
    }

    this.sourceLine = sourceLine;
    this.sourceFile = sourceFile;
    this.numLanguages = numLanguages; // needs to be validated?

    int numLanguagesFound = 0;
    int numAnswersFound = 0;

    StringTokenizer ans = new StringTokenizer(tsv, "\t", true);

    while (ans.hasMoreTokens()) {
      String s = null;
      s = ans.nextToken();

      if (s.equals("\t")) {
        ++field;
        if (field == 7) {
          ++numLanguagesFound; // since once that field has been entered, has successfully coded a
          // language as present
        }
        if (field == 9 && numLanguagesFound < numLanguages) {
          field = 5; // so that next element is readback for the next language
        }
        continue;
      }

      switch (field) {
          /* there should be one copy of each of these */
        case 0:
          conceptName = (new ExcelDecoder()).decode(s);
          break;
        case 1:
          localName = (new ExcelDecoder()).decode(s);
          break;
        case 2:
          externalName = (new ExcelDecoder()).decode(s);
          break;
        case 3:
          dependencies = (new ExcelDecoder()).decode(s);
          break;
        case 4:
          questionOrEvalTypeField = (new ExcelDecoder()).decode(s);
          break;
          /* there are as many copies of each of these are there are languages */
        case 5:
          readback.addElement((new ExcelDecoder()).decode(s));
          break;
        case 6:
          questionOrEval.addElement((new ExcelDecoder()).decode(s));
          break;
        case 7:
          answerChoicesStr.addElement((new ExcelDecoder()).decode(s));
          break;
        case 8:
          helpURL.addElement((new ExcelDecoder()).decode(s));
          break;
          /* there are as many copies of each of these are there are answers - rudimentary support for arrays? */
        case 9:
          {
            int i = 0;
            try {
              i = Integer.parseInt((new ExcelDecoder()).decode(s));
            } catch (NumberFormatException t) {
              Logger.getLogger(LoggerName).log(Level.SEVERE, "", t);
              if (AUTHORABLE) {
                setParseError(triceps.get("languageNum_must_be_an_integer") + t.getMessage());
              } else {
                setParseError("syntax error");
              }
              i = 0; // default language
            }
            if (i < 0 || i >= numLanguages) {
              if (AUTHORABLE) {
                setParseError(
                    triceps.get("languageNum_must_be_in_range_zero_to")
                        + (numLanguages - 1)
                        + "): "
                        + i);
              } else {
                setParseError("syntax error");
              }
              i = 0; // default language
            }
            answerLanguageNum = i;
          }
          break;
        case 10:
          questionAsAsked = (new ExcelDecoder()).decode(s);
          break;
        case 11:
          answerGiven = (new ExcelDecoder()).decode(s);
          break;
        case 12:
          comment = (new ExcelDecoder()).decode(s);
          break;
        case 13:
          answerTimeStampStr = (new ExcelDecoder()).decode(s);
          break;
        default:
          break; // ignore extras
      }
    }
    if (dependencies == null || dependencies.trim().length() == 0) {
      if (AUTHORABLE) {
        setParseError(triceps.get("dependencies_column_is_missing"));
      } else {
        setParseError("syntax error");
      }
    }
    if (localName != null && localName.trim().length() > 0) {
      localName = localName.trim();
      if (Character.isDigit(localName.charAt(0))) {
        if (AUTHORABLE) {
          setNamingError(triceps.get("localName_may_not_begin_with_a_digit") + localName);
        } else {
          setParseError("syntax error");
        }
        localName = "_" + localName;
      }
      if (!isNMTOKEN(localName)) {
        if (AUTHORABLE) {
          setNamingError(
              triceps.get("localName_should_only_contain_letters_digits_and_underscores")
                  + localName);
        } else {
          setParseError("syntax error");
        }
      }
    } else {
      setNamingError(triceps.get("localName_must_be_specified"));
    }

    parseQuestionOrEvalTypeField();

    if (questionOrEvalType == BADTYPE) {
      if (AUTHORABLE) {
        setParseError(triceps.get("invalid_questionOrEvalType") + questionOrEvalTypeField);
      } else {
        setParseError("syntax error");
      }
    }

    for (int i = 0; i < answerChoicesStr.size(); ++i) {
      parseAnswerOptions(i, (String) answerChoicesStr.elementAt(i));
    }

    if (datumType == Datum.INVALID) {
      if (AUTHORABLE) {
        setParseError(triceps.get("invalid_dataType"));
      } else {
        setParseError("syntax error");
      }
    }
  }