/* * RatingData.java * * Created on April 11, 2006, 3:54 PM */ import java.text.MessageFormat; import java.util.Locale; /** *
A convenient demonstration data model for the Rating component. To use
* multiple Rating instances in an application, one can create a
* Map of RatingData instances. In such a case, the
* grade property
* of a rating instance could be bound as follows (where "rating1" is the key
* used for the map entry):
*
* grade="#{SessionBean1.ratingMap.rating1.grade}"
*
* Here are the properties of a Rating component that can bind directly to the
* corresponding properties of a RatingData instance:
* grade, averageGrade, normalModeText,
* averageModeText
* gradeReadOnly, inAverageMode,
* hoverTexts.
*
The methods of this class are synchronized to prevent simultaneous access * by multiple threads associated with the same session.
* * @author Matthew Bohm */ public class RatingData { /** *The message formatting pattern to be used * for the average mode text.
*/ private static String averageModeTextPattern = "Average rating: {0,number,#.#} (from {1,number,integer} votes)"; /** *The normal mode text used when an appropriate hover text * is not available and a grade has not been saved.
*/ private static String simpleNormalModeText = ""; /** *The normal mode text used when an appropriate hover text * is not available and a grade has been saved.
*/ private static String simpleNormalModeTextSaved = "Saved"; /** *The normal mode text message formatting pattern used when an * appropriate hover text is available and a grade has not been saved.
*/ private static String normalModeTextPattern = "My rating: {0}"; /** *The normal mode text message formatting pattern used when an * appropriate hover text is available and a grade has been saved.
*/ private static String normalModeTextPatternSaved = "Saved: {0}"; /** *The "not interested" normal mode text when a grade has not * been saved.
*/ private static String notInterestedNormalModeText = "My rating: Not interested"; /** *The "not interested" normal mode text when a grade has * been saved.
*/ private static String notInterestedNormalModeTextSaved = "Saved: Not interested"; /** *The "clear" normal mode text when a grade has not * been saved.
*/ private static String clearNormalModeText = "No rating assigned"; /** *The "clear" normal mode text when a grade has * been saved.
*/ private static String clearNormalModeTextSaved = "No rating assigned"; /** *The message formatting object.
*/ private MessageFormat mf; /** *Construct a new RatingData instance and
* initialize the normalModeText and
* averageModeText properties.
*
Construct a new RatingData instance and
* initialize the normalModeText and
* averageModeText properties
* taking into account the hover texts.
*
Construct a new RatingData instance and
* initialize the normalModeText and
* averageModeText properties
* taking into account the hover texts,
* grade, average grade, vote count, and whether
* to show the grade as "saved."
*
Initialize the normalModeText and
* averageModeText properties taking into account the
* hover texts, grade, average grade, vote count, and whether
* to show the grade as "saved."
*
Get the locale used in message formatting the Rating texts.
*/ public synchronized Locale getLocale() { return this.mf.getLocale(); } /** *Set the locale used in message formatting the Rating texts.
*/ public synchronized void setLocale(Locale locale) { if (locale == null) { throw new NullPointerException(); } this.mf.setLocale(locale); } private int grade; /** * Get the user's grade. * @return The user's grade. */ public synchronized int getGrade() { return this.grade; } /** *In addition to setting the grade, the following operations
* will occur. The normal mode text
* will be updated. Furthermore, if the new grade is
* greater than 0 (since "not interested" is denoted by 1 and "clear"
* is denoted by 0), the average grade will be updated by counting this
* grade assignment as a vote. This is a crude algorithm, since it allows
* a single user to vote multiple times. However, that is precisely what
* we want for this demo. Along with this, the average mode text will be
* updated accordingly, based on the new average grade. Also, if we are
* assigning a non-zero grade, we set the gradeReadOnly entry for the
* rating instace to True. In this way, by binding the rating instance's
* gradeReadOnly property to the
* gradeReadOnly property of this RatingData,
* you can lock the user's grade once the user assigns it. (If you don't
* want this feature, simply don't bind the gradeReadOnly
* property to this RatingData.)
If the new grade is greater than 0, and the corresponding hover text
* is available, this method formats the normal mode text with that
* hover text and grade as arguments. Otherwise, it sets the normal mode
* text to the
* simpleNormalModeText,
* simpleNormalModeTextSaved,
* notInterestedNormalModeText,
* notInterestedNormalModeTextSaved,
* clearNormalModeText, or
* clearNormalModeTextSaved as appropriate, with no
* formatting changes.
*
* If the new grade is greater than 0, this method formats the average mode * text with the new average grade, vote count, and, if available, the * corresponding hover text. *
* @param grade The new grade. */ public synchronized void setGrade(int grade) { this.grade = grade; //update normalModeText String localNormalModeText = calculateNormalModeText(grade, true); setNormalModeText(localNormalModeText); if (grade > 0) { //update averageGrade with crude algorithm int localVoteCount = getVoteCount(); double localAverageGrade = getAverageGrade(); double totalGrade = localAverageGrade * localVoteCount; totalGrade += grade; localVoteCount++; localAverageGrade = totalGrade / localVoteCount; setVoteCount(localVoteCount); setAverageGrade(localAverageGrade); //update averageModeText Double averageGradeDouble = new Double(localAverageGrade); Integer voteCountInteger = new Integer(localVoteCount); String correspondingHoverText = null; //in case the pattern wants to make use of the corresponding hover text for this average grade if (this.hoverTexts != null) { int averageGradeAsInt = (int)Math.round(localAverageGrade); if (averageGradeAsInt > 0 && averageGradeAsInt <= this.hoverTexts.length) { correspondingHoverText = this.hoverTexts[averageGradeAsInt - 1]; } } Object[] args; if (correspondingHoverText == null) { args = new Object[]{averageGradeDouble, voteCountInteger}; } else { args = new Object[]{averageGradeDouble, voteCountInteger, correspondingHoverText}; } mf.applyPattern(this.averageModeTextPattern); String text = mf.format(args); setAverageModeText(text); } if (grade != 0) { //Set gradeReadOnly true. This will only take effect if the gradeReadOnly property is bound to this RatingData. //So if you want gradeReadOnly to be true once a grade is assigned, bind gradeReadOnly to this RatingData. //This enables you to "lock" the user's grade once the user assigns it. //If you don't want this feature, simply do not bind the gradeReadOnly property to this RatingData. setGradeReadOnly(true); } } private double averageGrade; /** * Get the average grade. * @return The average grade. */ public synchronized double getAverageGrade() { return this.averageGrade; } /** * Set the average grade. * @param averageGrade The new average grade. */ public synchronized void setAverageGrade(double averageGrade) { this.averageGrade = averageGrade; } private String normalModeText; /** * Get the normal mode text. * @return The normal mode text. */ public synchronized String getNormalModeText() { return this.normalModeText; } /** * Set the normal mode text. * @param normalModeText The new normal mode text. */ public synchronized void setNormalModeText(String normalModeText) { this.normalModeText = normalModeText; } private String averageModeText; /** * Get the average mode text. * @return The average mode text. */ public synchronized String getAverageModeText() { return this.averageModeText; } /** * Set the average mode text. * @param averageModeText The new average mode text. */ public synchronized void setAverageModeText(String averageModeText) { this.averageModeText = averageModeText; } private int voteCount; /** * Get the number of user votes. * @return The number of user votes. */ public synchronized int getVoteCount() { return this.voteCount; } /** * Set the number of user votes. * @param voteCount The new number of user votes. */ private void setVoteCount(int voteCount) { this.voteCount = voteCount; } private boolean gradeReadOnly; /** * Get whether the user's grade can be changed. * @return Whether the user's grade can be changed. */ public synchronized boolean isGradeReadOnly() { return this.gradeReadOnly; } /** * Set whether the user's grade can be changed. * @param gradeReadOnly Whether the user's grade can be changed. */ public synchronized void setGradeReadOnly(boolean gradeReadOnly) { this.gradeReadOnly = gradeReadOnly; } private boolean inAverageMode; /** * Get whether thisRatingData is in average mode.
* @return Whether this RatingData is in average mode.
*/
public synchronized boolean isInAverageMode() {
return this.inAverageMode;
}
/**
* Set whether this RatingData is in average mode.
* @param inAverageMode Whether this RatingData is in
* average mode.
*/
public synchronized void setInAverageMode(boolean inAverageMode) {
this.inAverageMode = inAverageMode;
}
private String[] hoverTexts;
/**
* Get the hover texts (i.e., for the "star" images only).
* @return The hover texts.
*/
public synchronized String[] getHoverTexts() {
return this.hoverTexts;
}
/**
* Set the hover texts (i.e., for the "star" images only).
* @param hoverTexts The new hover texts.
*/
public synchronized void setHoverTexts(String[] hoverTexts) {
this.hoverTexts = hoverTexts;
}
/**
*Calculate a new normal mode text.
*@return A new normal mode text. */ private String calculateNormalModeText(int localGrade, boolean saved) { String localNormalModeText = null; if (localGrade > 0) { if (hoverTexts != null && localGrade <= hoverTexts.length && hoverTexts[localGrade - 1] != null){ Object[] args = {hoverTexts[localGrade - 1], new Integer(localGrade)}; String pattern = saved ? this.normalModeTextPatternSaved : this.normalModeTextPattern; mf.applyPattern(pattern); localNormalModeText = mf.format(args); } else { localNormalModeText = saved ? this.simpleNormalModeTextSaved : this.simpleNormalModeText; } } if (localGrade == -1) { localNormalModeText = saved ? this.notInterestedNormalModeTextSaved : this.notInterestedNormalModeText; } else if (localGrade == 0) { localNormalModeText = saved ? this.clearNormalModeTextSaved : this.clearNormalModeText; } return localNormalModeText; } }