Index: samigo-app/pom.xml =================================================================== --- samigo-app/pom.xml (revision 93242) +++ samigo-app/pom.xml (working copy) @@ -123,6 +123,11 @@ commons-logging + commons-math + commons-math + 1.2 + + dom4j dom4j 1.6.1 Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages.properties =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages.properties (revision 93242) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages.properties (working copy) @@ -506,3 +506,8 @@ st_strong_agree = Strongly agree st_unacceptable = Unacceptable st_excellent = Excellent + +science_format_fin = Scientist format: Always use the point symbol as decimal separator and the letter 'E' for exponent. +science_format_fin_sample = For example: The Avogadro number is {6.022E24} +complex_format_fin = Complex numbers should be in the form (a + bi). We shall indicate explicitly both the real and the imaginary part. +complex_format_fin_sample = For example: we must put {1+1i} instead of {1+i}, also we must put {0+9i} instead of {9i}. Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages_es.properties =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages_es.properties (revision 93242) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/AuthorMessages_es.properties (working copy) @@ -418,3 +418,7 @@ st_unacceptable = Inaceptable st_excellent = Excelente +science_format_fin = Formato cient\u00EDfico: Utiliza siempre el punto como separador de decimales y la letra 'E' para el exponente. +science_format_fin_sample = Por ejemplo: El n\u00FAmero de Avogadro es {6.022E24} +complex_format_fin = Los n\u00FAmeros complejos deben tener el formato {a + bi}. Deberemos indicar expl\u00EDcitamente tanto la parte real como la imaginaria. +complex_format_fin_sample = Por ejemplo: no reconoce {1+i} (debemos poner {1+1i}) ni tampoco {9i} (debemos poner {0+9i}). Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages.properties =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages.properties (revision 93242) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages.properties (working copy) @@ -485,3 +485,6 @@ submission_allowed_2=time(s). submission_allowed_3=more times. +formatNumber_error=The value entered {0} is not a valid number +rangeNumber_error=The range of values between {0} and {1} must be increased +rangeformat_error=The value {0} in range {1} is not a valid real number format \ No newline at end of file Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages_es.properties =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages_es.properties (revision 93242) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/DeliveryMessages_es.properties (working copy) @@ -619,3 +619,6 @@ seeOrHide=Haga clic en la flecha inferior para mostrar u ocultar la lista de preguntas assessment_exit_warning_title=Aviso de salida de evaluaci\u00F3n +formatNumber_error=El valor introducido {0} no es un n\u00FAmero v\u00E1lido +rangeNumber_error=El rango de valores entre {0} y {1} debe ser creciente +rangeformat_error=El valor {0} del rango {1} no es un n\u00FAmero real en formato v\u00E1lido \ No newline at end of file Index: samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinQuestionValidator.java =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinQuestionValidator.java (revision 0) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinQuestionValidator.java (revision 0) @@ -0,0 +1,117 @@ +package org.sakaiproject.tool.assessment.jsf.validator; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.text.NumberFormat; +import java.util.Locale; +import java.util.StringTokenizer; + +import javax.faces.application.FacesMessage; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.validator.Validator; +import javax.faces.validator.ValidatorException; + +import org.apache.commons.math.complex.Complex; +import org.apache.commons.math.complex.ComplexFormat; +import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; + +public class FinQuestionValidator implements Validator { + + public FinQuestionValidator() { + // TODO Auto-generated constructor stub + } + + public void validate(FacesContext context, UIComponent component, Object value) + throws ValidatorException { + + String text = (String)value; + + int i = text.indexOf("{", 0); + int j = text.indexOf("}", 0); + + while (i != -1) { + String number = text.substring(i+1, j); + + StringTokenizer st = new StringTokenizer(number, "|"); + + if (st.countTokens() > 1) { + String number1 = st.nextToken().trim(); + String number2 = st.nextToken().trim(); + + // The first value in range must have a valid format + if (!isRealNumber(number1)) { + String error=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.DeliveryMessages", "rangeformat_error"); + MessageFormat format = new MessageFormat(error); + throw new ValidatorException(new FacesMessage(format.format(new String[] {number1, number}))); + } + + // The second value in range must have a valid format + if (!isRealNumber(number2)) { + String error=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.DeliveryMessages", "rangeformat_error"); + MessageFormat format = new MessageFormat(error); + throw new ValidatorException(new FacesMessage(format.format(new String[] {number2, number}))); + } + + // The range must be in increasing order + BigDecimal rango1 = new BigDecimal(number1); + BigDecimal rango2 = new BigDecimal(number2); + if (rango1.compareTo(rango2) != -1) { + String error=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.DeliveryMessages", "rangeNumber_error"); + MessageFormat format = new MessageFormat(error); + throw new ValidatorException(new FacesMessage(format.format(new String[] {number1, number2}))); + } + } + else { + // The number can be in a decimal format or complex format + if (!isRealNumber(number) && !isComplexNumber(number)) { + String error=(String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.DeliveryMessages", "formatNumber_error"); + MessageFormat format = new MessageFormat(error); + throw new ValidatorException(new FacesMessage(format.format(new String[] {number}))); + } + } + + i = text.indexOf("{", i+1); + if (j+1 < text.length()) j = text.indexOf("}", j+1); + else j = -1; + } + + } + + boolean isComplexNumber(String value) { + + boolean isComplex = true; + Complex complex=null; + try { + DecimalFormat df = (DecimalFormat)NumberFormat.getNumberInstance(Locale.US); + df.setGroupingUsed(false); + + // Numerical format ###.## (decimal symbol is the point) + ComplexFormat complexFormat = new ComplexFormat(df); + complex = complexFormat.parse(value); + + // This is because there is a bug parsing complex number. 9i is parsed as 9 + if (complex.getImaginary() == 0 && value.contains("i")) isComplex = false; + } catch (Exception e) { + isComplex = false; + } + + return isComplex; + } + + boolean isRealNumber(String value) { + + boolean isReal = true; + try { + // Number has decimal format? If no, Exception is throw + BigDecimal decimal = new BigDecimal(value); + + } catch (Exception e) { + isReal = false; + } + + return isReal; + } + +} \ No newline at end of file Index: samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinResponseValidator.java =================================================================== --- samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinResponseValidator.java (revision 0) +++ samigo-app/src/java/org/sakaiproject/tool/assessment/jsf/validator/FinResponseValidator.java (revision 0) @@ -0,0 +1,73 @@ +package org.sakaiproject.tool.assessment.jsf.validator; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.MessageFormat; +import java.text.NumberFormat; +import java.util.Locale; + +import javax.faces.application.FacesMessage; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.validator.Validator; +import javax.faces.validator.ValidatorException; + +import org.apache.commons.math.complex.Complex; +import org.apache.commons.math.complex.ComplexFormat; +import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil; + +public class FinResponseValidator implements Validator { + + public FinResponseValidator() { + // TODO Auto-generated constructor stub + } + + public void validate(FacesContext context, UIComponent component, Object value) + throws ValidatorException { + + // The number can be in a decimal format or complex format + if (!isRealNumber((String)value) && !isComplexNumber((String)value)) { + String error = (String)ContextUtil.getLocalizedString("org.sakaiproject.tool.assessment.bundle.DeliveryMessages", "formatNumber_error"); + MessageFormat format = new MessageFormat(error); + throw new ValidatorException(new FacesMessage(format.format(new String[] {(String)value}))); + } + + } + + boolean isComplexNumber(String value) { + + boolean isComplex = true; + Complex complex=null; + try { + // Numerical format ###.## (decimal symbol is the point) + DecimalFormat df = (DecimalFormat)NumberFormat.getNumberInstance(Locale.US); + df.setGroupingUsed(false); + + // Number has complex number? If no, ParseException is throw + ComplexFormat complexFormat = new ComplexFormat(df); + complex = complexFormat.parse(value); + + // This is because there is a bug parsing complex number. 9i is parsed as 9 + if (complex.getImaginary() == 0 && value.contains("i")) isComplex = false; + } catch (Exception e) { + isComplex = false; + } + + return isComplex; + } + + boolean isRealNumber(String value) { + + boolean isReal = true; + try { + // Number has decimal format? If no, Exception is throw + BigDecimal decimal = new BigDecimal(value); + + } catch (Exception e) { + isReal = false; + } + + return isReal; + } + +} Index: samigo-app/src/webapp/WEB-INF/faces-config.xml =================================================================== --- samigo-app/src/webapp/WEB-INF/faces-config.xml (revision 93242) +++ samigo-app/src/webapp/WEB-INF/faces-config.xml (working copy) @@ -1306,6 +1306,14 @@ + + finResponseValidator + org.sakaiproject.tool.assessment.jsf.validator.FinResponseValidator + + + finQuestionValidator + org.sakaiproject.tool.assessment.jsf.validator.FinQuestionValidator + Index: samigo-app/src/webapp/jsf/author/item/fillInNumeric.jsp =================================================================== --- samigo-app/src/webapp/jsf/author/item/fillInNumeric.jsp (revision 93242) +++ samigo-app/src/webapp/jsf/author/item/fillInNumeric.jsp (working copy) @@ -89,11 +89,19 @@

- + +
+ +
+ +
+ +
+
Index: samigo-app/src/webapp/jsf/delivery/item/deliverFillInNumeric.jsp =================================================================== --- samigo-app/src/webapp/jsf/delivery/item/deliverFillInNumeric.jsp (revision 93242) +++ samigo-app/src/webapp/jsf/delivery/item/deliverFillInNumeric.jsp (working copy) @@ -44,7 +44,9 @@ + value="#{answer.response}" onkeypress="return noenter()"> + + commons-logging
+ commons-math + commons-math + 1.2 + + javax.servlet servlet-api Index: samigo-services/src/java/org/sakaiproject/tool/assessment/services/GradingService.java =================================================================== --- samigo-services/src/java/org/sakaiproject/tool/assessment/services/GradingService.java (revision 93242) +++ samigo-services/src/java/org/sakaiproject/tool/assessment/services/GradingService.java (working copy) @@ -34,9 +34,13 @@ import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.text.ParseException; +import java.math.BigDecimal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.math.complex.Complex; +import org.apache.commons.math.complex.ComplexFormat; import org.sakaiproject.event.cover.EventTrackingService; import org.sakaiproject.service.gradebook.shared.GradebookService; import org.sakaiproject.spring.SpringBeanLocator; @@ -1387,9 +1391,12 @@ String studentanswer = ""; boolean range; boolean matchresult = false; - float studentAnswerNum,answer1Num,answer2Num,answerNum; - - if (data.getPublishedAnswerId() == null) { + ComplexFormat complexFormat = new ComplexFormat(); + Complex answerComplex = null; + Complex studentAnswerComplex = null; + BigDecimal answerNum = null, answer1Num = null, answer2Num = null, studentAnswerNum = null; + + if (data.getPublishedAnswerId() == null) { return false; } @@ -1422,9 +1429,9 @@ } try{ - answer1Num = Float.valueOf(answer1).floatValue(); + answer1Num = new BigDecimal(answer1); }catch(NumberFormatException ex){ - answer1Num = Float.NaN; + answer1Num = new BigDecimal(Float.toString(Float.NaN)) ; } log.debug("answer1Num= " + answer1Num); if (answer2 != null){ @@ -1432,15 +1439,15 @@ } try{ - answer2Num = Float.valueOf(answer2).floatValue(); + answer2Num = new BigDecimal(answer2); }catch(NumberFormatException ex){ - answer2Num = Float.NaN; + answer2Num = new BigDecimal(Float.toString(Float.NaN)); } log.debug("answer2Num= " + answer2Num); // Can accept increasing and decreasing ranges - if (answer1Num > answer2Num) { - float swap = answer1Num; + if (answer1Num.compareTo(answer2Num)==1){ + BigDecimal swap = answer1Num; answer1Num = answer2Num; answer2Num = swap; } @@ -1448,14 +1455,18 @@ if (data.getAnswerText() != null){ studentanswer= data.getAnswerText().trim().replace(',','.'); // in Spain, comma is used as a decimal point try{ - studentAnswerNum = Float.valueOf(studentanswer).floatValue(); + studentAnswerNum = new BigDecimal(studentanswer); }catch(NumberFormatException ex){ - studentAnswerNum = Float.NaN; + studentAnswerNum = new BigDecimal(Float.toString(Float.NaN)); //Temporal. Directamente contar\? como mala. } - log.debug("studentAnswerNum= " + studentAnswerNum); - if (!(Float.isNaN(studentAnswerNum) || Float.isNaN(answer1Num) || Float.isNaN(answer2Num))){ - matchresult=((answer1Num <= studentAnswerNum) && (answer2Num >= studentAnswerNum)) ; + log.debug("studentAnswerNum= " + studentAnswerNum); + boolean studentAnswerNumIsNaN = studentAnswerNum.compareTo(new BigDecimal(Float.toString(Float.NaN)))==0; + boolean answer1NumIsNaN = answer1Num.compareTo(new BigDecimal(Float.toString(Float.NaN)))==0; + boolean answer2NumIsNaN =answer2Num.compareTo(new BigDecimal(Float.toString(Float.NaN)))==0; + + if (!(studentAnswerNumIsNaN || answer1NumIsNaN || answer2NumIsNaN)){ + matchresult=((answer1Num.compareTo(studentAnswerNum)!=1) && (answer2Num.compareTo(studentAnswerNum)!=-1) ) ; } } @@ -1466,31 +1477,44 @@ } try{ - answerNum = Float.valueOf(answer).floatValue(); + answerNum = new BigDecimal(Float.valueOf(answer).toString()); }catch(NumberFormatException ex){ - answerNum = Float.NaN; + answerNum = new BigDecimal(Float.toString(Float.NaN)); // should not go here } log.debug("answerNum= " + answerNum); - + try { + answerComplex = complexFormat.parse(answer); + } catch(ParseException ex) { + log.debug("Number is not Complex: " + answer); + } if (data.getAnswerText() != null){ studentanswer= data.getAnswerText().trim().replace(',','.'); // in Spain, comma is used as a decimal point - try{ - studentAnswerNum = Float.valueOf(studentanswer).floatValue(); - }catch(NumberFormatException ex){ - studentAnswerNum = Float.NaN; - } - log.debug("studentAnswerNum= " + studentAnswerNum); - if (!(Float.isNaN(studentAnswerNum) || Float.isNaN(answerNum))){ - matchresult=(answerNum == studentAnswerNum) ; - } - } + if (answerNum!=null){ + try{ + studentAnswerNum = new BigDecimal(Float.valueOf(studentanswer).toString()); + }catch(NumberFormatException ex){ + studentAnswerNum = new BigDecimal(Float.toString(Float.NaN)); + } + log.debug("studentAnswerNum= " + studentAnswerNum); + boolean studentAnswerNumIsNaN = studentAnswerNum.compareTo(new BigDecimal(Float.toString(Float.NaN)))==0; + boolean answerNumIsNaN = answerNum.compareTo(new BigDecimal(Float.toString(Float.NaN)))==0; + if (!(studentAnswerNumIsNaN || answerNumIsNaN)){ + matchresult=(answerNum.compareTo(studentAnswerNum) == 0) ; + } + }else if (answerComplex != null) { + try { + studentAnswerComplex = complexFormat.parse(studentanswer); + log.debug("studentAnswerComplex= " + studentAnswerComplex.getReal() + "+" + studentAnswerComplex.getImaginary() + "i"); + } catch(ParseException ex) { + log.debug("Number is not Complex: " + studentanswer); + } + matchresult = (studentAnswerComplex != null && answerComplex.equals(studentAnswerComplex)); + } } - - - } + } return matchresult; }