source: trunk/quest-core-usability/src/main/java/de/ugoe/cs/quest/usability/TextInputStatisticsRule.java @ 442

Last change on this file since 442 was 442, checked in by pharms, 12 years ago

Initial import.

File size: 12.9 KB
Line 
1//-------------------------------------------------------------------------------------------------
2// Module    : $RCSfile: TextInputStatisticsRule.java,v $
3// Version   : $Revision: 0.0 $  $Author: pharms $  $Date: 16.07.2012 $
4// Project   : UsabilityEvaluationManager
5// Creation  : 2012 by pharms
6// Copyright : Patrick Harms, 2012
7//-------------------------------------------------------------------------------------------------
8package de.ugoe.cs.quest.usability;
9
10import java.text.DecimalFormat;
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15
16import de.ugoe.cs.quest.tasktrees.treeifc.TaskTree;
17import de.ugoe.cs.quest.tasktrees.treeifc.TaskTreeNode;
18import de.ugoe.cs.quest.tasktrees.treeifc.TextInputInteractionTask;
19import de.ugoe.cs.tasktree.guimodel.TextArea;
20import de.ugoe.cs.tasktree.guimodel.TextField;
21
22//-------------------------------------------------------------------------------------------------
23/**
24 * TODO comment
25 *
26 * @version $Revision: $ $Date: 16.07.2012$
27 * @author 2012, last modified by $Author: pharms$
28 */
29//-------------------------------------------------------------------------------------------------
30public class TextInputStatisticsRule implements de.ugoe.cs.quest.usability.UsabilityEvaluationRule
31{
32
33  //-----------------------------------------------------------------------------------------------
34  /* (non-Javadoc)
35   * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
36   */
37  //-----------------------------------------------------------------------------------------------
38  @Override
39  public UsabilityEvaluationResult evaluate(TaskTree taskTree)
40  {
41    TextInputStatistics statistics = new TextInputStatistics();
42    calculateStatistics(taskTree.getRoot(), statistics);
43   
44    UsabilityEvaluationResult results = new UsabilityEvaluationResult();
45    analyzeStatistics(statistics, results);
46   
47    return results;
48  }
49
50  //-----------------------------------------------------------------------------------------------
51  /**
52   * TODO: comment
53   *
54   * @param statistics
55   * @param results
56   */
57  //-----------------------------------------------------------------------------------------------
58  private void analyzeStatistics(TextInputStatistics statistics, UsabilityEvaluationResult results)
59  {
60    checkTextInputRatio(statistics, results);
61    checkTextFieldEntryRepetitions(statistics, results);
62  }
63
64  //-----------------------------------------------------------------------------------------------
65  /**
66   * TODO: comment
67   *
68   * @param statistics
69   * @param results
70   */
71  //-----------------------------------------------------------------------------------------------
72  private void checkTextInputRatio(TextInputStatistics       statistics,
73                                   UsabilityEvaluationResult results)
74  {
75    float allTextFieldInputs =
76      statistics.getNoOfTextFieldInputs() + statistics.getNoOfTextAreaInputs();
77   
78    float ratio = allTextFieldInputs / (float) statistics.getNoOfAllInteractions();
79   
80    UsabilityDefectSeverity severity = null;
81    if (ratio > 0.9)
82    {
83      severity = UsabilityDefectSeverity.HIGH;
84    }
85    else if (ratio > 0.7)
86    {
87      severity = UsabilityDefectSeverity.MEDIUM;
88    }
89    else if (ratio > 0.5)
90    {
91      severity = UsabilityDefectSeverity.INFO;
92    }
93   
94    if (severity != null)
95    {
96      Map<String, String> parameters = new HashMap<String, String>();
97      parameters.put("textInputRatio", DecimalFormat.getInstance().format(ratio * 100) + "%");
98     
99      results.addDefect
100        (new UsabilityDefect
101           (severity, UsabilityDefectDescription.TEXT_FIELD_INPUT_RATIO, parameters));
102    }
103  }
104
105  //-----------------------------------------------------------------------------------------------
106  /**
107   * TODO: comment
108   *
109   * @param statistics
110   * @param results
111   */
112  //-----------------------------------------------------------------------------------------------
113  private void checkTextFieldEntryRepetitions(TextInputStatistics       statistics,
114                                              UsabilityEvaluationResult results)
115  {
116    Map<String, Integer> words = new HashMap<String, Integer>();
117    int numberOfRepeatedWords = 0;
118    int maxRepetitions = 0;
119
120    for (int i = 0; i < statistics.getNoOfTextFieldInputs(); i++)
121    {
122      String[] fragments = statistics.getTextFieldInputFragments(i);
123      for (String fragment : fragments)
124      {
125        if (!"".equals(fragment.trim()))
126        {
127          Integer count = words.get(fragment);
128          if (count == null)
129          {
130            words.put(fragment, 1);
131          }
132          else
133          {
134            count++;
135            words.put(fragment, count);
136            maxRepetitions = Math.max(count, maxRepetitions);
137
138            if (count == 2)
139            {
140              // do not calculate repeated words several times
141              numberOfRepeatedWords++;
142            }
143          }
144        }
145      }
146    }
147   
148    UsabilityDefectSeverity severity = null;
149    if ((numberOfRepeatedWords > 10) || (maxRepetitions > 10))
150    {
151      severity = UsabilityDefectSeverity.HIGH;
152    }
153    else if ((numberOfRepeatedWords > 4) || (maxRepetitions > 4))
154    {
155      severity = UsabilityDefectSeverity.MEDIUM;
156    }
157    else if ((numberOfRepeatedWords > 2) || (maxRepetitions > 2))
158    {
159      severity = UsabilityDefectSeverity.LOW;
160    }
161    else if ((numberOfRepeatedWords > 1) || (maxRepetitions > 1))
162    {
163      severity = UsabilityDefectSeverity.INFO;
164    }
165   
166    if (severity != null)
167    {
168      Map<String, String> parameters = new HashMap<String, String>();
169      parameters.put("textRepetitionRatio", numberOfRepeatedWords + " repeated tokens, up to " +
170                     maxRepetitions + " repetitions per token");
171
172      results.addDefect
173        (new UsabilityDefect
174           (severity, UsabilityDefectDescription.TEXT_FIELD_INPUT_REPETITIONS, parameters));
175    }
176  }
177
178  //-----------------------------------------------------------------------------------------------
179  /**
180   * TODO: comment
181   *
182   * @param taskTree
183   * @param statistics
184   */
185  //-----------------------------------------------------------------------------------------------
186  private void calculateStatistics(TaskTreeNode node, TextInputStatistics statistics)
187  {
188    if (node instanceof TextInputInteractionTask)
189    {
190      calculateStatistics((TextInputInteractionTask) node, statistics);
191    }
192    else
193    {
194      if ((node.getChildren() == null) ||
195          (node.getChildren().size() == 0))
196      {
197        statistics.incrementNoOfOtherInteractionTasks();
198      }
199      else
200      {
201        for (TaskTreeNode child : node.getChildren())
202        {
203          calculateStatistics(child, statistics);
204        }
205      }
206    }
207  }
208
209  //-----------------------------------------------------------------------------------------------
210  /**
211   * TODO: comment
212   *
213   * @param taskTree
214   * @param statistics
215   */
216  //-----------------------------------------------------------------------------------------------
217  private void calculateStatistics(TextInputInteractionTask node, TextInputStatistics statistics)
218  {
219    String[] fragments = determineTextFragments(node.getEnteredText());
220   
221    if (node.getGUIElement() instanceof TextField)
222    {
223      statistics.addTextFieldInput(node, fragments);
224    }
225    else if (node.getGUIElement() instanceof TextArea)
226    {
227      statistics.addTextAreaInput(node, fragments);
228    }
229  }
230 
231  //-----------------------------------------------------------------------------------------------
232  /**
233   * TODO: comment
234   *
235   * @param enteredText
236   * @return
237   */
238  //-----------------------------------------------------------------------------------------------
239  private String[] determineTextFragments(String enteredText)
240  {
241    List<String> fragments = new ArrayList<String>();
242   
243    StringBuffer fragment = new StringBuffer();
244    char lastChar = 0;
245   
246    for (int i = 0; i < enteredText.length(); i++)
247    {
248      char currentChar = enteredText.charAt(i);
249     
250      if (!isEqualCharacterType(lastChar, currentChar))
251      {
252        // the previous fragment ended. so finalize it and start a new one
253        if ((fragment != null) && (fragment.length() > 0))
254        {
255          fragments.add(fragment.toString());
256          fragment = new StringBuffer();
257        }
258      }
259
260      fragment.append(currentChar);
261      lastChar = currentChar;
262    }
263   
264    if ((fragment != null) && (fragment.length() > 0))
265    {
266      fragments.add(fragment.toString());
267    }
268   
269    return fragments.toArray(new String[fragments.size()]);
270  }
271
272  //-----------------------------------------------------------------------------------------------
273  /**
274   * TODO: comment
275   *
276   * @param lastChar
277   * @param currentChar
278   * @return
279   */
280  //-----------------------------------------------------------------------------------------------
281  private boolean isEqualCharacterType(char char1, char char2)
282  {
283    return
284      ((char1 == char2) ||
285       (Character.isWhitespace(char1) && Character.isWhitespace(char2)) ||
286       (Character.isDigit(char1) && Character.isDigit(char2)) ||
287       (Character.isLetter(char1) && Character.isLetter(char2)) ||
288       (Character.isJavaIdentifierPart(char1) && Character.isJavaIdentifierPart(char2)));
289  }
290
291  //-------------------------------------------------------------------------------------------------
292  /**
293   * TODO comment
294   *
295   * @version $Revision: $ $Date: 16.07.2012$
296   * @author 2012, last modified by $Author: pharms$
297   */
298  //-------------------------------------------------------------------------------------------------
299  public class TextInputStatistics
300  {
301    /** */
302    private List<Object[]> mTextFieldInputs = new ArrayList<Object[]>();
303   
304    /** */
305    private List<Object[]> mTextAreaInputs = new ArrayList<Object[]>();
306   
307    /** */
308    private int mOtherInteractionsCount;
309   
310    //-----------------------------------------------------------------------------------------------
311    /**
312     * TODO: comment
313     * @param node
314     * @param fragments
315     *
316     */
317    //-----------------------------------------------------------------------------------------------
318    public void addTextFieldInput(TextInputInteractionTask node, String[] fragments)
319    {
320      mTextFieldInputs.add(new Object[] { node, fragments });
321    }
322
323    //-----------------------------------------------------------------------------------------------
324    /**
325     * TODO: comment
326     * @param node
327     * @param fragments
328     *
329     */
330    //-----------------------------------------------------------------------------------------------
331    public void addTextAreaInput(TextInputInteractionTask node, String[] fragments)
332    {
333      mTextAreaInputs.add(new Object[] { node, fragments });
334    }
335
336    //-----------------------------------------------------------------------------------------------
337    /**
338     * TODO: comment
339     *
340     * @return
341     */
342    //-----------------------------------------------------------------------------------------------
343    public int getNoOfAllInteractions()
344    {
345      return mTextFieldInputs.size() + mTextAreaInputs.size() + mOtherInteractionsCount;
346    }
347
348    //-----------------------------------------------------------------------------------------------
349    /**
350     * TODO: comment
351     *
352     * @return
353     */
354    //-----------------------------------------------------------------------------------------------
355    public int getNoOfTextFieldInputs()
356    {
357      return mTextFieldInputs.size();
358    }
359
360    //-----------------------------------------------------------------------------------------------
361    /**
362     * TODO: comment
363     *
364     * @param i
365     * @return
366     */
367    //-----------------------------------------------------------------------------------------------
368    public String[] getTextFieldInputFragments(int index)
369    {
370      return (String[]) mTextFieldInputs.get(index)[1];
371    }
372
373    //-----------------------------------------------------------------------------------------------
374    /**
375     * TODO: comment
376     *
377     * @return
378     */
379    //-----------------------------------------------------------------------------------------------
380    public int getNoOfTextAreaInputs()
381    {
382      return mTextAreaInputs.size();
383    }
384
385    //-----------------------------------------------------------------------------------------------
386    /**
387     * TODO: comment
388     *
389     * @param i
390     * @return
391     */
392    //-----------------------------------------------------------------------------------------------
393    public String[] getTextAreaInputFragments(int index)
394    {
395      return (String[]) mTextAreaInputs.get(index)[1];
396    }
397
398    //-----------------------------------------------------------------------------------------------
399    /**
400     * TODO: comment
401     *
402     */
403    //-----------------------------------------------------------------------------------------------
404    public void incrementNoOfOtherInteractionTasks()
405    {
406      mOtherInteractionsCount++;
407    }
408
409   
410  }
411
412}
Note: See TracBrowser for help on using the repository browser.