View Javadoc

1   /***
2    * Created on Jan 6, 2006, Copyright UC Regents
3    */
4   package org.telscenter.pas.steps.quickEditors.qti.assessment;
5   
6   import java.awt.BorderLayout;
7   import java.awt.Color;
8   import java.awt.Container;
9   import java.awt.Dimension;
10  import java.awt.FlowLayout;
11  import java.awt.event.ActionEvent;
12  import java.awt.event.ActionListener;
13  import java.awt.event.FocusEvent;
14  import java.awt.event.FocusListener;
15  import java.util.ArrayList;
16  import java.util.List;
17  
18  import javax.swing.BorderFactory;
19  import javax.swing.JButton;
20  import javax.swing.JCheckBox;
21  import javax.swing.JFrame;
22  import javax.swing.JLabel;
23  import javax.swing.JPanel;
24  import javax.swing.JScrollPane;
25  import javax.swing.JTextArea;
26  import javax.swing.border.CompoundBorder;
27  import javax.swing.undo.UndoManager;
28  
29  import net.miginfocom.swing.MigLayout;
30  import net.sf.sail.jaxb.extension.BlockInteractionType;
31  import net.sf.sail.jaxb.extension.JaxbQtiMarshallingUtils;
32  
33  import org.apache.commons.lang.StringUtils;
34  import org.imsglobal.xsd.imsqti_v2p0.AssessmentItemType;
35  import org.imsglobal.xsd.imsqti_v2p0.ItemBodyType;
36  import org.imsglobal.xsd.imsqti_v2p0.ObjectFactory;
37  import org.imsglobal.xsd.imsqti_v2p0.ResponseDeclarationType;
38  import org.telscenter.pas.common.ui.CommonUI;
39  import org.telscenter.pas.common.ui.panel.TextEditorPanel;
40  import org.telscenter.pas.steps.IAssessmentType;
41  import org.telscenter.pas.steps.IntroductionHtmlAware;
42  import org.telscenter.pas.steps.JaxbQtiNote;
43  import org.telscenter.pas.steps.JaxbQtiSelfAssessment;
44  import org.telscenter.pas.steps.JaxbQtiStep;
45  import org.telscenter.pas.steps.quickEditors.IQuickEditorControllable;
46  import org.telscenter.pas.ui.util.PasColors;
47  import org.telscenter.pas.util.JaxbQtiCreationUtils;
48  
49  import com.jgoodies.binding.beans.BeanAdapter;
50  
51  /***
52   * @author aperritano
53   * 
54   */
55  public class AssessmentQuickEditorUI extends JPanel implements IQuickEditorControllable, FocusListener {
56  	
57  	
58  	private static ObjectFactory jaxbFactory;
59  	private AssessmentItemType assessmentItem = null;
60  	private InteractionCardContainerUI interactionCardContainerUI;
61  
62  	private BeanAdapter beanAdapter;
63  
64  	private List<ResponseDeclarationType> responseDeclarations = new ArrayList<ResponseDeclarationType>();
65  	private JScrollPane listScroller;
66  
67  	private JPanel buttonPanel;
68  	private JaxbQtiStep assmtBean;
69  	private UndoManager undoManager;
70  	
71  	
72  	private int rimIndex = 0;
73  	/***
74  	 * @param assessmentBean 
75  	 * @param note
76  	 */
77  	public AssessmentQuickEditorUI(JaxbQtiStep assessmentBean) {
78  		super();
79  		this.assmtBean = assessmentBean;
80  		assessmentItem = assessmentBean.getAssessmentItem();
81  		this.init();
82  	}
83  
84  	
85  	/***
86  	 * @param noteBean
87  	 * @param undoManager2
88  	 */
89  	public AssessmentQuickEditorUI(JaxbQtiStep assessmentBean,
90  			UndoManager undoManager) {
91  		this.assmtBean = assessmentBean;
92  		assessmentItem = assessmentBean.getAssessmentItem();
93  		this.undoManager = undoManager;
94  		this.init();
95  		
96  		
97  	}
98  
99  
100 	/***
101 	 * This creates the button panel where you can add new interactions(text, choice)
102 	 * 
103 	 * @return
104 	 */
105 	protected JPanel createButtonPanel() {
106 		buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
107 
108 		String label = "";
109 		
110 		if( ((IAssessmentType)assmtBean).hasCorrectAnswer() ) {
111 			label = "Add a Multi Choice Question";
112 		} else {
113 			label = "Add a Survey Question";
114 		}
115 		JButton addMultiChoiceItem = new JButton(label);
116 		//CommonUI.makeEnhancedButton(addMultiChoiceItem);
117 
118 		buttonPanel.add(addMultiChoiceItem);
119 
120 		addMultiChoiceItem.addActionListener(new ActionListener() {
121 
122 			public void actionPerformed(ActionEvent e) {
123 				
124 				// extend interaction
125 				BlockInteractionType bi = JaxbQtiCreationUtils.addJaxbBlockInteraction(assmtBean,CardConstants.CHOICE_ASSMT, rimIndex++, responseDeclarations);
126 				AbstractCardUI inCard;
127 			
128 				/* if this step is a self check (self assessment), turn 
129 				   inlinefeedback on */
130 				if(assmtBean.hasInlineFeedback()) {
131 					bi.setHasInlineFeedback(true);
132 				}
133 				
134 				inCard = new InteractionCardUI(assmtBean, bi, assessmentItem.getResponseDeclaration(), beanAdapter, undoManager);
135 
136 				interactionCardContainerUI.addInteractionCard(inCard, true);
137 				listScroller.getVerticalScrollBar().setValue(
138 						listScroller.getVerticalScrollBar().getMaximum());
139 				
140 				AssessmentQuickEditorUI.this.revalidate();
141 			}
142 		});
143 
144 		JButton addTextItem = new JButton("Add an Open-Response Question");
145 
146 		addTextItem.addActionListener(new ActionListener() {
147 
148 			public void actionPerformed(ActionEvent e) {
149 				// extend interaction
150 				
151 				//create a new text interaction 
152 				BlockInteractionType bi = JaxbQtiCreationUtils.addJaxbBlockInteraction(assmtBean,CardConstants.TEXT_ASSMT, rimIndex++, responseDeclarations);
153 				
154 				AbstractCardUI innyCard;
155 				
156 				innyCard = new InteractionCardUI(assmtBean, bi,assessmentItem.getResponseDeclaration(), beanAdapter, undoManager);
157 				
158 				interactionCardContainerUI.addInteractionCard(innyCard, true);
159 				listScroller.getVerticalScrollBar().setValue(
160 						listScroller.getVerticalScrollBar().getMaximum());
161 				
162 				AssessmentQuickEditorUI.this.revalidate();
163 				
164 			}
165 		});
166 
167 		//CommonUI.makeEnhancedButton(addTextItem);
168 		
169 		//self check steps should not have the add text button
170 		if(!assmtBean.getType().equals(JaxbQtiSelfAssessment.TYPE)) {
171 			buttonPanel.add(addTextItem);
172 		}
173 		
174 		buttonPanel.setOpaque(false);
175 		return buttonPanel;
176 	}
177 
178 	/***
179 	 * @return
180 	 */
181 	protected JPanel createLockStudentAnswers() {
182 		JPanel lockPanel = new JPanel(new BorderLayout(0,0));
183 		
184 		JCheckBox lockBox = new JCheckBox("Lock Student Answers - When selected, student can only answer once");
185 		lockBox.setSelected(assmtBean.isLockStudentAnswers());
186 		lockBox.setOpaque(false);
187 		lockBox.addActionListener(new ActionListener(){
188 
189 			public void actionPerformed(ActionEvent e) {
190 				JCheckBox source = (JCheckBox) e.getSource();
191 				assmtBean.setLockStudentAnswers(source.isSelected());
192 				System.out.println("isLocked " + source.isSelected());
193 			}});
194 //		JLabel label = new JLabel();
195 //		label.setIcon(new ImageIcon(PasCommonIconProvider.getImage("help.png")));
196 //		label.setVerticalAlignment(JLabel.TOP);
197 //		label.setToolTipText("<html>The size of the response field gives students a sense of how much<br>they should write in response to the question</html>");
198 //		label.setOpaque(false);
199 		lockBox.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
200 		//lockPanel.add(new JLabel("Lock Student Answer:"),BorderLayout.WEST);
201 		lockPanel.add(lockBox, BorderLayout.WEST);
202 		lockPanel.setOpaque(false);
203 		return lockPanel;
204 	}
205 	
206 	/***
207 	 * This is a layout with no assessment interactions
208 	 */
209 	private void createNullLayout() {
210 		setLayout(new BorderLayout(0, 0));
211 		setBackground(PasColors.qtiAssessmentQuickEditorBackgroundColor);
212 
213 		JLabel messageLabel = new JLabel("This assessment has zero items.");
214 		messageLabel.setOpaque(false);
215 		JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
216 		panel.setBorder(BorderFactory.createEmptyBorder(4, 4, 0, 4));
217 		panel.add(messageLabel);
218 		panel.setOpaque(false);
219 
220 		add(panel, BorderLayout.CENTER);
221 	}
222 
223 	/***
224 	 * This is the basic UI methods, runs through the list of interactions and creates their authoring cards
225 	 */
226 	protected void createUI() {
227 		setLayout(new BorderLayout(0, 0));
228 		setBackground(PasColors.qtiAssessmentQuickEditorBackgroundColor);
229 
230 		JPanel overAllPanel = new JPanel(new BorderLayout(0,0));
231 		overAllPanel.setBackground(this.getBackground());
232 		
233 		JPanel htmlPanel = new JPanel(new MigLayout("wrap 1, insets 0"));
234 		htmlPanel.setBackground(this.getBackground());
235 		htmlPanel.setOpaque(false);
236 		
237 		//if it has an htmlIntroduction add an html panel
238 		if( assmtBean instanceof IntroductionHtmlAware) {
239 			String introductionHtml = ((IntroductionHtmlAware) assmtBean).getIntroductionHtml();
240 			if( introductionHtml != null)
241 				htmlPanel.add(createHTMLIntroArea(StringUtils.stripToEmpty(introductionHtml)));
242 			else
243 				htmlPanel.add(createHTMLIntroArea(""));
244 			
245 		}
246 		
247 		boolean canLockAnswers = ((IAssessmentType)assmtBean).canLockAnswers();
248 		if( canLockAnswers) {
249 			htmlPanel.add(createLockStudentAnswers());
250 		}
251 		
252 		overAllPanel.add(htmlPanel, BorderLayout.NORTH);
253 		interactionCardContainerUI = new InteractionCardContainerUI(
254 				this.assessmentItem);
255 		if (this.assessmentItem == null
256 				|| this.assessmentItem.getItemBody().getBlockElementGroup().size() == 0) {
257 			
258 			AbstractCardUI<BlockInteractionType> nc = new InteractionCardUI(null,null, null, beanAdapter, undoManager);
259 			
260 		} else {
261 			List<Object> interactions = this.assessmentItem.getItemBody().getBlockElementGroup();
262 			for (Object interaction : interactions) {
263 				AbstractCardUI nc = new InteractionCardUI(assmtBean,(BlockInteractionType) interaction, assessmentItem.getResponseDeclaration(), undoManager);
264 				interactionCardContainerUI.addInteractionCard(nc);
265 				
266 				/* if this step is a self check (self assessment), turn 
267 				   inlinefeedback on */
268 				if(assmtBean.hasInlineFeedback()) {
269 					((BlockInteractionType) interaction).setHasInlineFeedback(true);
270 				}
271 			}// for
272 		}// if
273 		
274 		overAllPanel.add(interactionCardContainerUI,BorderLayout.CENTER);
275 		
276 		listScroller = new JScrollPane();
277 		listScroller.getViewport().add(overAllPanel);
278 		listScroller
279 				.setBackground(PasColors.qtiAssessmentQuickEditorListScrollerBackgroundColor);
280 		listScroller
281 				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
282 		listScroller
283 				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
284 		listScroller.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0));
285 
286 		JPanel scrollerPanel = new JPanel(new BorderLayout(0, 0));
287 		scrollerPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 0, 4));
288 		scrollerPanel.add(listScroller, BorderLayout.CENTER);
289 		scrollerPanel.setOpaque(false);
290 
291 		JPanel bp = createButtonPanel();
292 		add(scrollerPanel, BorderLayout.CENTER);
293 		if( bp != null)
294 		add(bp, BorderLayout.SOUTH);
295 	}
296 
297 	/***
298 	 * Create HTML text area
299 	 * 
300 	 * @return
301 	 */
302 	protected JPanel createHTMLIntroArea(String html) {
303 		
304 		String trimToNull = StringUtils.trimToNull(html);
305 		
306 		if( trimToNull == null )
307 			html = " ";
308 		JTextArea htmlArea = new JTextArea(html);
309 		
310 		TextEditorPanel ppanel = new TextEditorPanel(htmlArea,new Dimension(CardConstants.TEXT_AREA_LENTH, 125));
311 		htmlArea.setBackground(ppanel.getBackground());
312 		JButton jb = ppanel.getEditButton();
313 		 if( jb != null ) {
314 			 jb.addActionListener(CommonUI.createHTMLTidyEditActionlistener());
315 		 }// if
316 		
317 		if( undoManager != null)
318 			htmlArea.getDocument().addUndoableEditListener(undoManager);
319 		htmlArea.addFocusListener(new FocusListener() {
320 
321 			public void focusGained(FocusEvent e) {}
322 
323 			public void focusLost(FocusEvent e) {
324 				JTextArea source = (JTextArea) e.getSource();
325 
326 				String promptText = source.getText();
327 
328 				((IntroductionHtmlAware)assmtBean).setIntroductionHtml(promptText);
329 				
330 			}});
331 		
332 		CompoundBorder b = BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2), BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.WHITE), "Introduction Text"));
333 		
334 		ppanel.setBorder(b);
335 		ppanel.setOpaque(false);
336 		
337 		return ppanel;
338 	}
339 	
340 	/***
341 	 * Get the assessmentItem 
342 	 * 
343 	 * @return
344 	 */
345 	public AssessmentItemType getAssessmentItem() {
346 		return assessmentItem;
347 	}
348 
349 	/***
350 	 * Set the assessmentItem
351 	 * 
352 	 * @param item
353 	 */
354 	public void setAssessmentItem(AssessmentItemType assessmentItem) {
355 		if (assessmentItem == null) {
356 			createUI();
357 		} else {
358 			this.assessmentItem = assessmentItem;
359 
360 			removeAll();
361 			createUI();
362 		}// 
363 	}
364 
365 	
366 	
367 	/***
368 	 * Initialize the interface.
369 	 * 
370 	 * @param item
371 	 */
372 	public void init() {
373 		if (assessmentItem == null) {
374 			assessmentItem = JaxbQtiMarshallingUtils.getJaxbObjectFactory().createAssessmentItemType();
375 			//need id
376 			ItemBodyType itemBody = JaxbQtiMarshallingUtils.getJaxbObjectFactory().createItemBodyType();
377 			assessmentItem.setItemBody(itemBody);
378 			// collect the interactions and responseDeclarations
379 			List<BlockInteractionType> interactions = new ArrayList<BlockInteractionType>();
380 			//itemBody.setInteractions(interactions);
381 			//itemBody.getBlockElementGroup().addAll(interactions);
382 			//List<ResponseDeclarationType> responseDeclarations = new ArrayList<ResponseDeclarationType>();
383 			//assessmentItem.getResponseDeclaration().addAll(responseDeclarations);
384 			assmtBean.setAssessmentItem(assessmentItem);
385 			if( assmtBean instanceof IntroductionHtmlAware) {
386 				((IntroductionHtmlAware) assmtBean).setIntroductionHtml(CardConstants.htmlStartTag + CardConstants.DEFAULT_INTRODUCTION_HTML + CardConstants.htmlEndTag);
387 				
388 			}
389 			createUI();
390 		} else {
391 			removeAll();
392 			createUI();
393 		}// 
394 	}
395 	
396 	
397 	
398 	/***
399 	 * basic event for focus
400 	 * 
401 	 * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
402 	 */
403 	public void focusGained(FocusEvent e) {
404 		System.out.println("QTIAssessmentQuickEditorUI.focusGained()");
405 	}
406 
407 	/***
408 	 * Basic event for focus
409 	 *  
410 	 * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
411 	 */
412 	public void focusLost(FocusEvent e) {
413 		System.out.println("QTIAssessmentQuickEditorUI.focusLost()");
414 	}
415 
416 	/***
417 	 * 
418 	 * Basic Event for focus
419 	 * 
420 	 * @see org.telscenter.pas.steps.quickEditors.IQuickEditorControllable#getControllPanel()
421 	 */
422 	public JPanel getControllPanel() {
423 		return buttonPanel;
424 	}
425 
426 	/***
427 	 * Tester method
428 	 * 
429 	 * @param args
430 	 */
431 	public static void main(String[] args) {
432 		JFrame frame = new JFrame("note quick editor test");
433 
434 		Container contentPane = frame.getContentPane();
435 
436 		JButton showButton = new JButton("show ui");
437 
438 		showButton.addActionListener(new ActionListener() {
439 
440 			public void actionPerformed(ActionEvent e) {
441 
442 				JFrame frame = new JFrame("note quick editor test");
443 
444 				Container contentPane = frame.getContentPane();
445 				AssessmentQuickEditorUI noteUI = new AssessmentQuickEditorUI(null);
446 				noteUI.setAssessmentItem(new AssessmentItemType());
447 				contentPane.add(noteUI);
448 				frame.setSize(noteUI.getPreferredSize());
449 				frame.setVisible(true);
450 			}
451 
452 		});
453 		contentPane.add(showButton);
454 
455 		frame.setSize(200, 200);
456 		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
457 		frame.setVisible(true);
458 	}
459 
460 	/* (non-Javadoc)
461 	 * @see org.telscenter.pas.steps.quickEditors.IQuickEditorControllable#getUndoManager()
462 	 */
463 	public UndoManager getUndoManager() {
464 		return undoManager;
465 	}
466 
467 	/* (non-Javadoc)
468 	 * @see org.telscenter.pas.steps.quickEditors.IQuickEditorControllable#setUndoManager(javax.swing.undo.UndoManager)
469 	 */
470 	public void setUndoManager(UndoManager undoManager) {
471 		this.undoManager = undoManager;
472 	}
473 	
474 }