View Javadoc

1   /***
2    * 
3    */
4   package org.telscenter.pas.steps;
5   
6   import java.awt.BorderLayout;
7   import java.awt.Color;
8   import java.awt.event.ActionEvent;
9   import java.awt.event.ActionListener;
10  import java.awt.event.ComponentEvent;
11  import java.awt.event.ComponentListener;
12  import java.awt.Dimension;
13  import java.awt.FlowLayout;
14  import java.awt.GridBagConstraints;
15  import java.awt.GridBagLayout;
16  import java.io.InputStream;
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Random;
22  
23  import javax.swing.BorderFactory;
24  import javax.swing.BoxLayout;
25  import javax.swing.ButtonGroup;
26  import javax.swing.ImageIcon;
27  import javax.swing.JButton;
28  import javax.swing.JComponent;
29  import javax.swing.JLabel;
30  import javax.swing.JPanel;
31  import javax.swing.JRadioButton;
32  import javax.swing.JScrollPane;
33  import javax.swing.JTextArea;
34  import javax.swing.border.CompoundBorder;
35  
36  import net.sf.sail.core.entity.ISock;
37  
38  import java.util.logging.Logger;
39  
40  import org.apache.commons.io.IOUtils;
41  import org.telscenter.pas.beans.PasProject;
42  import org.telscenter.pas.beans.PasStep;
43  import org.telscenter.pas.common.ui.CommonUI;
44  import org.telscenter.pas.common.ui.panel.SimpleGradientPanel;
45  import org.telscenter.pas.navigation.PasProjectNavigationTaskPanel;
46  import org.telscenter.pas.service.INavigationService;
47  import org.telscenter.pas.service.NavigateAction;
48  import org.telscenter.pas.steps.actions.LeaveStudentAssessmentAction;
49  import org.telscenter.pas.steps.domain.BlockInteraction;
50  import org.telscenter.pas.steps.domain.ChoiceInteraction;
51  import org.telscenter.pas.steps.domain.FeedbackInline;
52  import org.telscenter.pas.steps.domain.FeedbackModal;
53  import org.telscenter.pas.steps.domain.ResponseDeclaration;
54  import org.telscenter.pas.steps.actions.ChallengeQuestionCheckAction;
55  import org.telscenter.pas.steps.domain.SimpleChoice;
56  import org.telscenter.pas.ui.icons.PasCommonIconProvider;
57  import org.telscenter.pas.ui.util.PasColors;
58  import org.telscenter.pas.util.QTIUtils;
59  import org.xhtmlrenderer.simple.XHTMLPanel;
60  
61  /***
62   * @author aperritano
63   *
64   */
65  public class ChallengeQuestionUI extends AssessmentUI {
66  
67  	/***
68  	 * Logger for this class
69  	 */
70  	static final Logger logger = Logger
71  			.getLogger(StudentAssessmentUI.class.getName());
72  	
73  	private static final long serialVersionUID = 1L;
74  
75  	protected String introductionHtml = ""; //$NON-NLS-1$
76  
77  	protected JButton submitQuestionsButton;
78  
79  	protected String QUESTION_CARD = "QUESTION_CARD"; //$NON-NLS-1$
80  
81  	protected String RESULT_CARD = "RESULT_CARD"; //$NON-NLS-1$
82  
83  	//stores the feedbacks 
84  	private HashMap<String, JLabel> feedbackLabels;
85  
86  	//stores the radiobuttons
87  	private HashMap<String, JRadioButton> radiobuttons;
88  	
89  	//FIX: this is hacked to disable submit checking
90  	public boolean hasSubmited = true;
91  
92  	public boolean toLeaveStep = false;
93  
94  	protected JPanel submitButtonPanel;
95  
96  	protected LeaveStudentAssessmentAction leaveAction;
97  	
98  	//the check to determine the action to take according to 
99  	//whether the current answer selected was correct or not
100 	private JButton processAttemptButton;
101 	
102 	//the link via which to revisit the evidence step before proceeding with
103 	//the challenge question for another attempt
104 	private JButton gotoStepButton;
105 
106 	//holds icon for incorrect answer
107 	private ImageIcon redX;
108 
109 	//holds label for the score
110 	private JLabel scoreLabel;
111 
112 	//stores the inline feedback text
113 	private JLabel inlineFbTextLabel;
114 
115 	//a radiobutton for multiple choice
116 	private JRadioButton scButton;
117 
118 	//panel for holding all the multiple choice selections to choose answer from
119 	private JPanel choicePanel; 
120 	
121 	private List<JRadioButton> choiceButtonList = new ArrayList<JRadioButton>();
122 	
123 	private static final int CHOICE_CONTENT_WIDTH = 300;
124 	
125 	private static final int INLINE_FEEDBACK_WIDTH = 300;
126 	
127 	private static final int INLINE_FEEDBACK_HEIGHT = 100;
128 	//private static final Color CORRECT_INLINE_COLOR = Color.GREEN;
129 
130 	//private static final Color INCORRECT_INLINE_COLOR = Color.RED;
131 
132 	//holds set of values for the attempt prefixes for reporting (e.g. 1st attempt, 2nd attempt, etc)
133 	public static final String indexes[] = { "1st", "2nd", "3rd", "4th", "5th",
134 			"6th", "7th", "8th", "9th", "10th" };
135 	
136 	public ChallengeQuestionUI(Assessment assmt) {
137 		super(assmt);
138 	} 
139 	
140 	/***
141 	 * 
142 	 * creates and integrates all the buttons, feedback icons, score label, prompt panel, choices panel, feedback panel for showing in VLE 
143 	 * the final step for the actual VLE output itself is controlled by getComponent in ChallengeQuestion.java
144 	 * 
145 	 * @return
146 	 */
147 	@Override
148 	protected void initUI() {		
149 		if( assessment.getAssessmentItem() == null || assessment.getAssessmentItem().getItemBody().getInteractions().size() == 0 ) {
150 			this.setLayout(new FlowLayout(FlowLayout.CENTER));
151 			this.setOpaque(false);
152 			JLabel noLabel = new JLabel("This Note has no items.");
153 			noLabel.setOpaque(false);
154 			this.add(noLabel, BorderLayout.CENTER);
155 			return;
156 		}
157 		List<BlockInteraction> interactions = assessment.getAssessmentItem().getItemBody().getInteractions();
158 		radiobuttons = new HashMap<String, JRadioButton>();
159 		feedbackLabels = new HashMap<String, JLabel>();
160 		gotoStepButton = createGotoStepButton();
161 		gotoStepButton.setVisible(false);
162 		clearFeedbackInline();
163 		
164 		JPanel titlePanel = createTitlePanel();
165 		JPanel scorePanel = createScorePanel();
166 		JPanel buttonPanel = createButtonPanel();			
167 		JPanel cqChoicePanel = cQ_choiceInteractionPanel(interactions, titlePanel, scorePanel, buttonPanel);
168 		
169 		// put them in a scrollpanel for the ca
170 		JPanel scrollerPanel = createScrollerPanel(cqChoicePanel);
171 
172 		cardPanel.add(scrollerPanel, QUESTION_CARD);		
173 
174 		SimpleGradientPanel mainPanel = createSimpleGradientPanel();
175 		GridBagConstraints c = createGridBagConstraint();
176 		mainPanel.add(cardPanel, c);
177 
178 		// disable buttons if...1) no more attempts left or 2) student has
179 		// answered and student got correct answer
180 		Object correctAnswer = ((ChallengeQuestion)assessment).correctAnswer();
181 		getCorrectFeedback(correctAnswer);
182 
183 		updateScoreLabelStatus();
184 		mainPanel.validate();
185 		
186 		this.setLayout(new BorderLayout(0,0));
187 		this.add(mainPanel,BorderLayout.CENTER);
188 
189 	}
190 
191 /**************************************** START OF LAYOUT ****************************************************/	
192 	/***
193 	 * @return c
194 	 * creates the position of the component to be shown via grid bag layout
195 	 */
196 	private GridBagConstraints createGridBagConstraint() {
197 		GridBagConstraints c = new GridBagConstraints();
198 		// c.fill = GridBagConstraints.HORIZONTAL;
199 		c.fill = GridBagConstraints.BOTH;
200 
201 		c.weightx = 1;
202 		c.gridx = 0;
203 		c.gridy = 0;
204 	//	mainPanel.add(bannerPanel, c);
205 
206 		c.gridx = 0;
207 		c.gridy = 0;
208 		//mainPanel.add(introPanel, c);
209 
210 		c.weighty = 1;
211 		c.gridx = 0;
212 		c.gridy = 0;
213 		c.fill = GridBagConstraints.BOTH;
214 		return c;
215 	}
216 
217 /******************************** ENDING OF LAYOUT ********************************************************/
218 /******************************** THE MAIN PANELS **********************************************************
219  * TITLE, SCORE, BUTTON, PROMPT & CHOICE, CHOICE & FEEDBACK, CHOICE INTERACTION, GRADIENT, AND SCROLLING PANELS
220  */
221 	/***
222 	 * creates the challenge question title panel
223 	 * 
224 	 * 
225 	 * @return titlePanel
226      */
227 	private JPanel createTitlePanel(){
228 		String labelValue = "<html><body>" + "<p style='font-size:16;font-weight:bold;text-align:left;'>" +
229 							"Challenge Question" + "</body></html>";
230 		
231 		JPanel titlePanel = new JPanel();
232 		titlePanel.setLayout(new BorderLayout(0,0));
233 		
234 		titlePanel.add(new JLabel(labelValue), BorderLayout.CENTER);
235 		return titlePanel;
236 	}
237 
238 	/***
239 	 * creates the challenge question score panel, with score report shown in blue text
240 	 * 
241 	 * 
242 	 * @return scorePanel
243      */
244 	private JPanel createScorePanel(){
245 		JPanel scorePanel = new JPanel();
246 		scorePanel.setOpaque(false);
247 		scoreLabel = new JLabel();
248 		scoreLabel.setForeground(Color.BLUE);
249 		scorePanel.add(scoreLabel, BorderLayout.CENTER);
250 		return scorePanel;
251 	}
252 
253 	/***
254 	 * creates the check action button panel
255 	 * 
256 	 * 
257 	 * @return buttonPanel
258      */
259 	private JPanel createButtonPanel(){
260 		ChallengeQuestionCheckAction checkAction = getCQCheckAction();	
261 		processAttemptButton = new JButton();
262 		processAttemptButton.setAction(checkAction);
263 		processAttemptButton.setEnabled(false);
264 		CommonUI.makeEnhancedButton(processAttemptButton);
265 		JPanel buttonPanel = new JPanel();
266 		buttonPanel.add(processAttemptButton, BorderLayout.NORTH);
267 		buttonPanel.setPreferredSize(new Dimension(buttonPanel.getPreferredSize().width, 20));
268 		buttonPanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
269 		return buttonPanel;
270 	}
271 
272 	/***
273 	 * gets choice and feedback panel, adds the score panel, prompt panel, and the choice & feedback panel to a single panel to return
274 	 * 
275 	 * @param scorePanel
276 	 * @param promptPanel
277 	 * @param choicePanel
278 	 * @param buttonPanel
279 	 * @return allPartsPanel
280      */
281 	private JPanel getPromptAndChoicePanel(JPanel scorePanel, JComponent promptPanel, JPanel choicePanel, JPanel buttonPanel){
282 		JPanel allPartsPanel = new JPanel();
283 		allPartsPanel.setLayout(new BoxLayout(allPartsPanel, BoxLayout.Y_AXIS));
284 		allPartsPanel.setBackground(Color.white);
285 		allPartsPanel.putClientProperty(ITEM_COMPLETED, new Boolean(false));
286 		JPanel choiceAndFeedbackPanel = getChoiceAndFeedbackPanel(choicePanel, buttonPanel);	
287 		allPartsPanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
288 		allPartsPanel.add(scorePanel,BorderLayout.NORTH);
289 		allPartsPanel.add(promptPanel, BorderLayout.CENTER);
290 		allPartsPanel.add(choiceAndFeedbackPanel,BorderLayout.SOUTH);
291 		return allPartsPanel;
292 	}
293 
294 	/***
295 	 * adds the multiple choice panel, inline feedback text label, and check action button panel to
296 	 * choice and feedback panel
297 	 * 
298 	 * @param choicePanel
299 	 * @param buttonPanel
300 	 * @return choiceAndFeedbackPanel
301 	 */
302 	private JPanel getChoiceAndFeedbackPanel(JPanel choicePanel, JPanel buttonPanel) {
303 		JPanel choiceAndFeedbackPanel = new JPanel();
304 		choiceAndFeedbackPanel.setLayout(new BoxLayout(choiceAndFeedbackPanel, BoxLayout.Y_AXIS));
305 		choiceAndFeedbackPanel.setPreferredSize(new Dimension(450,350));
306 		choiceAndFeedbackPanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
307 
308 		JPanel inlineFbTextPanel = new JPanel();
309 		inlineFbTextLabel = new JLabel();
310 		inlineFbTextLabel.setPreferredSize(new Dimension(INLINE_FEEDBACK_WIDTH,INLINE_FEEDBACK_HEIGHT));
311 		inlineFbTextPanel.add(inlineFbTextLabel);
312 		inlineFbTextPanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
313 		if(!inlineFbTextLabel.getText().equals("")){
314 			inlineFbTextPanel.setPreferredSize(new Dimension(INLINE_FEEDBACK_WIDTH/2, INLINE_FEEDBACK_HEIGHT));
315 			
316 		}else{
317 			inlineFbTextPanel.setPreferredSize(new Dimension(0,0));
318 		}
319 		choiceAndFeedbackPanel.add(choicePanel);
320 		choiceAndFeedbackPanel.add(inlineFbTextPanel);
321 		choiceAndFeedbackPanel.add(buttonPanel);
322 	
323 		return choiceAndFeedbackPanel;
324 	}
325 
326 	/***
327 	 * creates a simple gradient panel for background
328 	 * 
329 	 * @return mainPanel
330 	 */
331 	private SimpleGradientPanel createSimpleGradientPanel() {
332 		SimpleGradientPanel mainPanel = new SimpleGradientPanel();
333 		mainPanel.setDirection(SimpleGradientPanel.VERTICAL);
334 		mainPanel.setStartColor(PasColors.compactNavBackgroundStartColor);
335 		mainPanel.setEndColor(PasColors.compactNavBackgroundEndColor);
336 		mainPanel.setLayout(new GridBagLayout());
337 		return mainPanel;
338 	}
339 
340 	/***
341 	 * Creates all the interactions
342 	 * 
343 	 * @param interactions
344 	 * @param titlePanel
345 	 * @param scorePanel
346 	 * @param buttonPanel
347 	 * @return a panel with all the parts needed for this challenge question - title, prompt and multiple choices, and the check action button panel
348 	 */
349 	protected JPanel cQ_choiceInteractionPanel(List<BlockInteraction> interactions, JPanel titlePanel, JPanel scorePanel, JPanel buttonPanel) {
350 		JPanel mainPanel = new JPanel();
351 		mainPanel.setBackground(PasColors.pandaPanelBackgroundColor);
352 		mainPanel.setLayout(new BorderLayout(0, 0));
353 
354 		JPanel tPane = new JPanel();
355 		tPane.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
356 		JPanel allPanel = null;
357 		
358 		choicePanel = new JPanel();
359 		choicePanel.setLayout(new BoxLayout(choicePanel, BoxLayout.Y_AXIS));
360 		choicePanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
361 		
362 		JComponent createPromptPanel=null;
363 			
364 		//traverses through the interactions, reorders the choices for scrambling the choices around 
365 		//in the challenge question and adds the updated choice interaction to the corresponding 
366 		//radio buttons and group for the multiple choice functionality, and then the panels are added
367 		for (int i = 0; i < interactions.size(); i++) {
368 			ChoiceInteraction<String> choiceInteraction = (ChoiceInteraction<String>) interactions
369 					.get(i);
370 			choiceInteraction = reOrderChoices(choiceInteraction);
371 			createPromptPanel = createPromptPanel(choiceInteraction);
372 			createPromptPanel.setBackground(PasColors.challengeQuestionChoiceInteractionTextAreaColor);
373 		    setChoicesToButtons(choiceInteraction);
374 			JPanel promptAndChoicePanel = getPromptAndChoicePanel(scorePanel, createPromptPanel, choicePanel, buttonPanel);
375 			allPanel = new JPanel();
376 			allPanel.setLayout(new BoxLayout(allPanel, BoxLayout.Y_AXIS));
377 			allPanel.add(titlePanel);
378 			allPanel.add(promptAndChoicePanel);
379 			allPanel.add(gotoStepButton);
380 			tPane.add(allPanel, BorderLayout.CENTER);
381 		}
382 		
383 		mainPanel.add(tPane, BorderLayout.CENTER);
384 
385 		return mainPanel;
386 	}
387 
388 	/***
389 	 * Creates the scroller panel for adding the challenge question panel created
390 	 * 
391 	 * @param questionsPanel
392 	 * @return scrollerPanel
393 	 */
394 
395 	private JPanel createScrollerPanel(JPanel questionsPanel) {
396 		JScrollPane questionScroller = new JScrollPane(questionsPanel);
397 		questionScroller
398 				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
399 		questionScroller
400 				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
401 		questionScroller.setBorder(BorderFactory.createEmptyBorder());
402 		questionScroller.getVerticalScrollBar().setValue(
403 				questionScroller.getVerticalScrollBar().getMaximum());
404 		questionScroller.setOpaque(false);
405 		JPanel scrollerPanel = new JPanel(new BorderLayout(0, 0));
406 		scrollerPanel.add(questionScroller, BorderLayout.CENTER);
407 		scrollerPanel.setOpaque(true);
408 		scrollerPanel.setBackground(PasColors.pandaPanelBackgroundColor);
409 		return scrollerPanel;
410 	}
411 	
412 /*********************************CLOSING OF THE PANELS ********************************************************/	
413 /*********************************** BUTTON CREATION ***********************************************************
414 	 * createGotoStepButton
415 	 * getChoiceButton
416 	 */ 	
417 		/***
418 		 * Creates goto step button
419 		 * 
420 		 * @param thisPanel
421 		 * @param j
422 		 * @param step
423 		 * @return
424 		 */
425 		public JButton createGotoStepButton() {
426 			PasProjectNavigationTaskPanel navigationTaskPanel = ((ChallengeQuestion) assessment).getPasProject().getPanel();
427 			PasStep gotoStep = ((ChallengeQuestion) assessment).getGotoStep();
428 			INavigationService navigationService = ((ChallengeQuestion) assessment).getNavigationService();
429 			JButton gotoStepButton = new JButton(new NavigateAction(gotoStep, navigationService, navigationTaskPanel));
430 			gotoStepButton.setHorizontalTextPosition(JLabel.LEFT);
431 			gotoStepButton.setContentAreaFilled(false);
432 			gotoStepButton.setFont(gotoStepButton.getFont().deriveFont(16.0f));
433 			gotoStepButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0));
434 			gotoStepButton.setText("Go to Evidence Step");
435 
436 			gotoStepButton.addActionListener(new ActionListener() {
437 				public void actionPerformed(ActionEvent e) { //if the link is clicked, the code below is performed
438 					PasProject pasProject = ((ChallengeQuestion) assessment).getPasProject();
439 					ISock<String> navigationLogSock = pasProject.getNavigationLogSock(); //retrieves the navigation log
440 					if (navigationLogSock != null) {
441 						//registers the navigation to the goto step into the navigation log so that the challenge question is unlocked 
442 						navigationLogSock.add(pasProject.getItemLog("step_open", (((ChallengeQuestion) assessment).getGotoStep())));
443 					}
444 				}
445 			});
446 			CommonUI.makeLink(gotoStepButton);
447 			return gotoStepButton;
448 		}
449 			
450 		/***
451 		 * Creates multiple choice radio button with action listener for setting student selection
452 		 * 
453 		 * @param studentAnswer
454 		 * @param sc
455 		 * @param choiceInteraction
456 		 * @return button
457 		 */
458 		private JRadioButton getChoiceButton(String studentAnswer, SimpleChoice<String> sc, ChoiceInteraction<String> choiceInteraction){
459 			JRadioButton button = new JRadioButton();
460 //		 if student chose this choice before, mark as selected
461 			if (studentAnswer != null
462 					&& studentAnswer.equals(sc.getIdentifier())) {
463 				button.setSelected(true);
464 			} else {
465 				button.setSelected(false);
466 			}
467 			button.setOpaque(false);
468 			button.putClientProperty(QTIUtils.SIMPLE_CHOICE, sc);
469 			button.putClientProperty(RESPONSE_ID, choiceInteraction
470 					.getResponseIdentifier());
471 			// ... all in one container
472 
473 			button.addActionListener(new ActionListener() {
474 
475 				public void actionPerformed(ActionEvent e) {
476 					JRadioButton radioButton = (JRadioButton) e.getSource();
477 
478 					if (radioButton.isSelected()) {
479 						SimpleChoice<String> sc = ((SimpleChoice<String>) radioButton
480 								.getClientProperty(QTIUtils.SIMPLE_CHOICE));
481 
482 						assessment.getResponses().put(
483 								(String) radioButton
484 										.getClientProperty(RESPONSE_ID),
485 								sc.getIdentifier());
486 
487 						logger.info("responses: "
488 								+ assessment.getResponses().toString());
489 						processAttemptButton.setEnabled(true);
490 					}
491 				}
492 			});
493 
494 			return button;
495 		}
496 
497 /********************************************************************************************************/
498 /*********************************** BUTTON ACTION ***********************************************************/
499 		/***
500 		 * disables the 'check answer' button after an attempt has been made (until the next time the cq step is visited)
501 		 * as long as one has more tries remaining or did not yet choose the correct answer
502 		 * 
503 		 *  
504 		 * 
505 		 * @return
506 		 */
507 				
508 		public void disableProcessAttemptButton() {
509 			this.processAttemptButton.setEnabled(false);
510 		}
511 
512 		/***
513 		 * Greys out SimpleChoice radio buttons
514 		 * 
515 		 * @param buttonIdentifier
516 		 * @param isCorrect
517 		 * @return
518 		 */
519 		
520 		public void disableRadioButtons(Object buttonIdentifier, boolean isCorrect) {
521 			JRadioButton rb = radiobuttons.get(buttonIdentifier);
522 
523 			for (JRadioButton radioButton : radiobuttons.values()) {
524 				if(!radioButton.equals(rb)){
525 					radioButton.setEnabled(false);
526 				}else{
527 					if(isCorrect){
528 						rb.setIcon(greenCheck);
529 					}else{
530 						rb.setIcon(redX);
531 					}
532 				}
533 			}
534 		}
535 
536 		/*** 
537 		 * selects the radio button and also sets the appropriate image icon
538 		 * 
539 		 * @param buttonIdentifier
540 		 * @param isCorrect
541 		 */
542 		public void selectRadioButton(Object buttonIdentifier, boolean isCorrect) {
543 			JRadioButton rb = radiobuttons.get(buttonIdentifier);
544 			if (isCorrect) {
545 				rb.setIcon(greenCheck);
546 				rb.setForeground(new Color(0,220,0));
547 			} else {
548 				rb.setIcon(redX);
549 				rb.setForeground(Color.RED);
550 			}
551 			rb.setSelected(true);
552 		}
553 
554 		/***
555 		 * Removes the icons associated with all of the radio buttons and reverts to
556 		 * default
557 		 * 
558 		 * @return 
559 		 */
560 		public void clearRadioButtonIcons() {
561 			for (JRadioButton radioButton : radiobuttons.values()) {
562 				radioButton.setIcon(null);
563 				radioButton.setForeground(Color.BLACK);
564 			}
565 		}
566 
567 /************************************* END BUTTON ACTION ***************************************************/	
568 /************************************ CHOICE INTERACTIONS **************************************************/
569 		/***
570 		 * reorders the choices once the cq step is refreshed (revisited) as long as the correct answer was not chosen yet
571 		 * updates the score board and report
572 		 * clears all the inline feedbacks
573 		 * disables the process attempt button until the user chooses a choice
574 		 * 
575 		 * @return
576 		 */
577 		
578 		@SuppressWarnings("cast")
579 		public void updateCqUI_Interactions(){
580 			String correctAnswer = ((ChallengeQuestion)assessment).correctAnswer();
581 			String studentAnswer = ((ChallengeQuestion)assessment).lastAnswer();
582 			boolean correctAnswerChosen = correctAnswer.equals(studentAnswer);
583 			int attemptNum = ((ChallengeQuestion)assessment).numStudentAttempts();
584 			boolean outOfAttempts = attemptNum >= ((ChallengeQuestion)assessment).getMaxAttempts();
585 			
586 			updateScoreLabelStatus();
587 			processAttemptButton.setEnabled(false);
588 			
589 			//if(!correctAnswerChosen && !outOfAttempts){
590 				scoreLabel.setVisible(true);
591 				this.inlineFbTextLabel.setText("");
592 				clearRadioButtonIcons();
593 				List<BlockInteraction> theInteractions = assessment.getAssessmentItem().getItemBody().getInteractions();
594 				choiceButtonList = new ArrayList<JRadioButton>();
595 
596 				//traverses through the interactions, reorders the choices for scrambling the choices around 
597 				//in the challenge question 
598 				for (int i = 0; i < theInteractions.size(); i++) {
599 					ChoiceInteraction<String> choiceInteraction = (ChoiceInteraction<String>) theInteractions.get(i);
600 					choiceInteraction = reOrderChoices(choiceInteraction);
601 					theInteractions.set(i, (BlockInteraction)choiceInteraction);
602 					radiobuttons.clear();
603 					choicePanel.removeAll();
604 					inlineFbTextLabel.setText("");
605 					setupChoiceButtonPanel(choiceInteraction, "", true);
606 				}	
607 				
608 				assessment.getAssessmentItem().getItemBody().setInteractions(theInteractions);
609 			}
610 		//}
611 		
612 		/***
613 		 * assigns each choice content to a radio button for displaying as part of the multiple choice button
614 		 * panel
615 		 * 
616 		 * @return
617 		 */
618 		private void setupChoiceButtonPanel(ChoiceInteraction<String> ci, String answer, boolean feedbackAdjusted){
619 			List<SimpleChoice<String>> theChoices = ci.getSimpleChoices();
620 			ButtonGroup group = new ButtonGroup(); // this is for the radio button
621 												   // functionality
622 												   // (one-choice-at-a-time)
623 			for (SimpleChoice<String> sc : theChoices) {
624 				scButton = getChoiceButton(answer,sc,ci);			
625  
626 				JPanel jp = new JPanel();
627 				jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS));
628 				jp.add(scButton);
629 				jp.setOpaque(false);
630 				if(!feedbackAdjusted)
631 					adjustFeedback(sc);
632 				String theContent = sc.getContent();
633 				/*
634 				theContent = wrapInlineText(theContent, CHOICE_CONTENT_WIDTH);
635 				sc.setContent(theContent); */
636 				scButton.setText(theContent.trim());
637 				scButton.setIcon(null);
638 				choicePanel.add(jp, BorderLayout.NORTH);
639 				radiobuttons.put(sc.getIdentifier(), scButton);				
640 				choiceButtonList.add(scButton);				
641 				group.add(scButton);
642 			}	
643 		}
644 		
645 		/***
646 		 * Randomizes the choices
647 		 * @param interaction
648 		 * @return
649 		 */
650 		private ChoiceInteraction<String> reOrderChoices(ChoiceInteraction<String> interaction){
651 			String prompt = interaction.getPrompt();
652 			String promptAttrs = "<P style='font-size:20;text-align:center;'>";
653 			String initHtml = "<html><body>";
654 			String finalHtml = "</P></body></html>";			
655 			String updatedPrompt = initHtml + promptAttrs + extractBody(prompt) + finalHtml;		
656 			List<SimpleChoice<String>> choices = interaction.getSimpleChoices();
657 			interaction.setPrompt(updatedPrompt);		
658 			List<SimpleChoice<String>> newChoices = new ArrayList<SimpleChoice<String>>(choices.size());
659 		    Random rand = new Random();
660 		    while (choices.size() > 0) {
661 		    	newChoices.add(choices.remove(rand.nextInt(choices.size())));
662 		    }
663 		
664 		    interaction.setSimpleChoices(newChoices);		
665 			return interaction;
666 		}
667 		
668 
669 		/***
670 		 * maps the student answer to the corresponding radio button, and maps the choice content to the radio buttons as well
671 		 * 
672 		 * @param choiceInteraction
673 		 * @return
674 		 */
675 		private void setChoicesToButtons(
676 				ChoiceInteraction<String> choiceInteraction) {
677 			choiceButtonList = new ArrayList<JRadioButton>();
678 			
679 			String studentAnswer = Assessment.getStudentAnswer(assessment,
680 					choiceInteraction);
681 
682 			setupChoiceButtonPanel(choiceInteraction, studentAnswer, false);
683 			choiceInteractionToChoiceButtonLists.put(choiceInteraction,
684 				choiceButtonList);
685 		}
686 
687 /*********************************************************************************************************/
688 
689 /**************************** SCORE STATUS **************************************************
690 	* This section determines what the score status should be - correct, wrong, or out of attempts
691 	* the corresponding status is shown on the score label and also stored in the reportText for 
692 	* displaying in show all work
693 ********************************************************************************************/
694 	
695 	/***
696 	 * Displays a status message on the bottom of the screen Either: -- What
697 	 * score the student can get -- What score the student has gotten
698 	 * 
699 	 * @return 
700 	 */
701 	public void updateScoreLabelStatus() {
702 		int sNumAttempts = ((ChallengeQuestion)assessment).numStudentAttempts();
703 		List<Integer> scores = ((ChallengeQuestion) assessment).getScores();		
704 		String correctAnswer = ((ChallengeQuestion)assessment).correctAnswer();
705 		String feedbackSize = "<p style='font-size:16;font-weight:bold;text-align:center;'>";
706 		String origText = null;
707 		String initHtml = "<html><body>";
708 		String finalHtml = "</p></body></html>";
709 		
710 	//	for(int i = 1; i < scores.size(); i++){
711 	//		scores.set(i,0);
712 	//	}
713 
714 		setScoreLabel(sNumAttempts, scores, correctAnswer);
715 		
716 		origText = scoreLabel.getText();
717 		scoreLabel.setText(initHtml + feedbackSize + origText + finalHtml);	
718 		scoreLabel.setVisible(false);
719 	}
720 
721 	/***
722 	 * sets the score label outcome of the choice student selected and chose as their current answer, 
723 	 * where the outcome is dependent on whether the most recent answer selected was correct,
724 	 * incorrect, or the number of attempts have been reached or exceeded 
725 	 * 
726 	 * @param sNumAttempts
727 	 * @param scores
728 	 * @param correctAnswer
729 	 * @return
730 	 */
731 	private void setScoreLabel(int sNumAttempts, List<Integer> scores,
732 			String correctAnswer) {
733 		String lastAnswer = ((ChallengeQuestion)assessment).lastAnswer();
734 		
735 		if (correctAnswer.equals(lastAnswer)){
736 			int index = sNumAttempts-1;
737 			String corrFeedback = indexes[index] + " try";
738 			setCorrectAnswerLabel(index, corrFeedback, scores);
739 			
740 		} else if (sNumAttempts >= scores.size()) {
741 			scoreLabel.setText("Sorry, you're out of tries.");
742 		} else {
743 			String attmptFeedback = indexes[sNumAttempts] + " try";
744 			setWrongAnswerLabel(sNumAttempts, attmptFeedback, scores);
745 		}
746 		
747 	}
748 	
749 	/***
750 	 * updates the score label if the answer is wrong; if there are points, the points are shown in the label 
751 	 * otherwise they are not shown
752 	 * 
753 	 * @param sNumAttempts
754 	 * @param attmptFeedback
755 	 * @param scores
756 	 * @return
757 	 */
758 	private void setWrongAnswerLabel(int sNumAttempts, String attmptFeedback, List<Integer> scores) {
759 		if(scores.get(sNumAttempts) > 0){
760 			scoreLabel.setText(attmptFeedback + " for "
761 				               + scores.get(sNumAttempts) + " points.");
762 		}else{
763 			scoreLabel.setText(attmptFeedback + ".");
764 		}
765 	}
766 	
767 	/***
768 	 * updates the score label if the answer is correct; if there are points, the points are shown in the label 
769 	 * otherwise they are not shown
770 	 * 
771 	 * @param index
772 	 * @param corrFeedback
773 	 * @param scores
774 	 * @return
775 	 */
776 	private void setCorrectAnswerLabel(int index, String corrFeedback, List<Integer> scores) {			
777 		if(scores.get(index) > 0){
778 			scoreLabel.setText(corrFeedback + " for " + scores.get(index)
779 				+ " points.");
780 		}else{
781 			scoreLabel.setText(corrFeedback + ".");
782 		}
783 	}
784 
785 /*********************************** ENDS SCORE STATUS **************************************************/	
786 /************************************ FEEDBACK INLINE  **************************************************/
787 
788 	/***
789 	 * set all inline feedback labels to be invisible
790 	 * 
791 	 * @return 
792 	 */
793 	public void clearFeedbackInline() {
794 		if (feedbackLabels == null)
795 			return;
796 
797 		for (JLabel label : feedbackLabels.values()) {
798 			label.setVisible(false);
799 		}
800 	}
801 	
802 	/***
803 	 * disables the radio buttons, shows the correct inline feedback with corresponding radio button chosen 
804 	 * 
805 	 * @param correctAnswer
806 	 */
807 	private void getCorrectFeedback(Object correctAnswer) {
808 		int numStudentAttempts = ((ChallengeQuestion)assessment).numStudentAttempts();
809 		int maxAttempts = ((ChallengeQuestion)assessment).getMaxAttempts();
810 		String lastAnswer = ((ChallengeQuestion)assessment).lastAnswer();
811 		
812 		if (numStudentAttempts >= maxAttempts
813 				|| lastAnswer != null && lastAnswer.equals(correctAnswer)) {
814 			disableRadioButtons(correctAnswer,false);
815 			displayCorrectFeedbackInline();
816 			selectRadioButton(correctAnswer, true); // select w/ correct image
817 			// icon
818 		}
819 	}
820 
821 	/***
822 	 * shows the correct inline feedback 
823 	 * 
824 	 * @return
825 	 */
826 	public void displayCorrectFeedbackInline() {
827 		String newFeedbackInline = ((ChallengeQuestion)assessment).getCorrectFeedbackInline();
828 		displayInlineFeedbackLabel(newFeedbackInline);
829 	}
830 	
831 	/***
832 	 * show last attempted choice's feedback
833 	 * 
834 	 * precondition: there is at least one previous answer in studentSock
835 	 * @return 
836 	 */
837 	public void displayLastFeedbackInline() {
838 		String newFeedbackInline = ((ChallengeQuestion)assessment).getLastFeedbackInline(assessment);
839 		displayInlineFeedbackLabel(newFeedbackInline);	
840 	}
841 
842 
843 	private void displayInlineFeedbackLabel(String newFeedbackInline){
844 		if(!newFeedbackInline.equals("")){
845 			inlineFbTextLabel.setText(newFeedbackInline);
846 			inlineFbTextLabel.setForeground(Color.BLUE);
847 			inlineFbTextLabel.setVisible(true);
848 		}
849 	}
850 	
851 	
852 	/***
853 	 * wraps the inline feedback, adds it to a feedback label and puts it to the list of feedbackLabels 
854 	 * 
855 	 * @param sc
856 	 * @return 
857 	 */
858 
859 	private void adjustFeedback(SimpleChoice<String> sc){
860 		int adjustedWidth = 50;
861 		String inlineFeedbackText = null;
862 		FeedbackInline inlineFeedback = sc.getFeedbackInline();
863 
864 		if (inlineFeedback != null) {
865 			inlineFeedbackText = (String) inlineFeedback
866 					.getContent();			
867 			inlineFeedbackText = wrapInlineText(inlineFeedbackText,adjustedWidth);
868 			inlineFeedback.setContent(inlineFeedbackText);
869 		}
870 			JLabel fiLabel = new JLabel();
871 			// save each (choice, JLabel) pair so the itempanel can
872 			// be updated easily
873 			feedbackLabels.put(sc.getIdentifier(), fiLabel);
874 			fiLabel.setLayout(new BoxLayout(fiLabel,BoxLayout.Y_AXIS));
875 			fiLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
876 			
877 	}
878 	
879 
880 	/***
881 	 * @return label
882 	 */
883 	protected JLabel createNoNoteTakenLabel() {
884 		JLabel noNoteTakenLabel = new JLabel(Messages
885 				.getString("Note.NOTE_NOT_TAKEN")); //$NON-NLS-1$
886 		noNoteTakenLabel.setFont(noNoteTakenLabel.getFont().deriveFont(
887 				14.0f));
888 		noNoteTakenLabel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0,
889 				0));
890 		noNoteTakenLabel.setOpaque(false);
891 		return noNoteTakenLabel;
892 	}
893 	
894 	/***
895 	 * @return panel - an empty box layout panel with components to be aligned vertically
896 	 */
897 	protected JPanel createVerticalBoxLayoutPanel(){
898 		JPanel panel = new JPanel();
899 		panel.setOpaque(false);
900 		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
901 		return panel;
902 	}
903 	
904 	/***
905 	 * Creates a simple, border-layout panel
906 	 * @return JPanel border layout
907 	 */
908 	protected JPanel createBorderLayoutPanel() {
909 		JPanel borderPanel = new JPanel();
910 		borderPanel.setLayout(new BorderLayout(0, 0));
911 		borderPanel.setOpaque(false);
912 		return borderPanel;
913 	}
914 	
915 	
916 	
917 	/***
918 	 * @return CompoundBorder 
919 	 */
920 	protected CompoundBorder createCompoundBorder(){
921 		return BorderFactory
922 		.createCompoundBorder(BorderFactory.createEmptyBorder(
923 				0, 8, 0, 0), BorderFactory.createLineBorder(
924 				PasColors.noteReportLineBorderColor, 1));
925 	}
926 
927 	/***
928 	 * @param answer - creates a textarea for the answer to be stored into, 
929 	 * in this case red (if not answered) 
930 	 * or black (if answered)
931 	 * @return answerArea
932 	 */
933 	protected JTextArea createAnswerArea(String answer) {
934 		JTextArea answerArea = new JTextArea();
935 		answerArea.setOpaque(true);
936 		answerArea.setBackground(PasColors.noteReportTextAreaColor);		
937 		
938 		if(answer.indexOf("NOT ANSWERED") > -1){
939 			answerArea.setForeground(Color.RED);
940 		}else{
941 			answerArea.setForeground(Color.BLACK);				
942 		}
943 		
944 		answerArea.setText(answer);
945 		answerArea.setBorder(CommonUI.createEtchedBorder());
946 		answerArea.setBorder(BorderFactory.createMatteBorder(0,0,1,0,Color.BLACK));
947 		return answerArea;
948 	}
949 /************************************END FEEDBACK INLINE  **************************************************/
950 /************************************************** TEXT PROCESSING **************************************************/	
951 	/***
952 	 * wraps the inline text but cutting off each line to a specified width and continuing 
953 	 * the remainder of the text, repeating this process until the string has been fully wrapped
954 	 */	
955 	public String wrapInlineText(String inlineFeedbackText, int adjustedWidth){
956 		String initHtml = "<html><body>";
957 		String finalHtml = "</body></html>";
958 		String finalStr = "";	
959 		int lastIndex = 0;
960 
961 		inlineFeedbackText = inlineFeedbackText.trim();
962 
963 		while(inlineFeedbackText.length() > adjustedWidth){
964 			String substri = inlineFeedbackText.substring(0,adjustedWidth);
965 			lastIndex = substri.lastIndexOf(" ");
966 			finalStr = finalStr + substri.substring(0,lastIndex) + "\n";
967 			inlineFeedbackText = inlineFeedbackText.substring((int)lastIndex, inlineFeedbackText.length());
968 
969 		}
970 		return initHtml + finalStr + inlineFeedbackText.substring(0,inlineFeedbackText.length()) + finalHtml;		
971 	}
972 
973 	/***
974 	 * extracts everything between the body tags
975 	 * 
976 	 * @param prompt
977 	 * @return extractedBody 
978 	 */	
979 
980 	private String extractBody(String prompt) {
981 		int start = prompt.indexOf("<body>");
982 		int end = prompt.indexOf("</body>");
983 	
984 		String extractedBody = "";
985 		
986 		if (start != -1 && end != -1) {
987 			extractedBody = prompt.substring(start+6, end);
988 		}			
989 		return extractedBody;
990 	}
991 	
992 
993 	
994 /***********************************************END TEXT PROCESSING **************************************************/
995 /*********************************************************************************************************************/
996 /***********************************************GETTERS AND SETTERS **************************************************/
997 
998 	/***
999 	 * @return the check action for the check action button, the logic of which proceeds to 
1000 	 * ChallengeQuestionCheckAction
1001 	 */
1002 	protected ChallengeQuestionCheckAction getCQCheckAction() {
1003 		ChallengeQuestionCheckAction checkAction = new ChallengeQuestionCheckAction(
1004 				assessment.getAssessmentItem(), assessment.getResponses(),
1005 				assessment.getResponseDeclarationToSocks(),
1006 				(ChallengeQuestion) assessment);
1007 		return checkAction;
1008 	}
1009 	
1010 	/***
1011 	 * @return the gotoStepButton
1012 	 */
1013 	public JButton getGotoStepButton() {
1014 		return gotoStepButton;
1015 	}
1016 
1017 	/***
1018 	 * @param gotoStepButton the gotoStepButton to set
1019 	 */
1020 	public void setGotoStepButton(JButton gotoStepButton) {
1021 		this.gotoStepButton = gotoStepButton;
1022 	}
1023 	
1024 /************************************************************************************************************************/
1025 
1026 }