1 /***
2 * Created on Jan 6, 2006, Copyright UC Regents
3 */
4 package org.telscenter.pas.steps.quickEditors.qti.assessment;
5
6 import info.clearthought.layout.TableLayout;
7
8 import java.awt.BorderLayout;
9 import java.awt.Component;
10 import java.awt.Container;
11 import java.awt.Dimension;
12 import java.awt.FlowLayout;
13 import java.awt.Font;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.ActionListener;
16 import java.awt.event.FocusEvent;
17 import java.awt.event.FocusListener;
18 import java.io.Serializable;
19 import java.math.BigInteger;
20 import java.util.List;
21
22 import javax.swing.BorderFactory;
23 import javax.swing.ButtonGroup;
24 import javax.swing.ImageIcon;
25 import javax.swing.JButton;
26 import javax.swing.JCheckBox;
27 import javax.swing.JComboBox;
28 import javax.swing.JFrame;
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.SwingConstants;
35 import javax.swing.ToolTipManager;
36 import javax.swing.undo.UndoManager;
37
38 import net.miginfocom.swing.MigLayout;
39 import net.sf.sail.jaxb.extension.BlockInteractionType;
40
41 import org.imsglobal.xsd.imsqti_v2p0.AssessmentItemType;
42 import org.imsglobal.xsd.imsqti_v2p0.ChoiceInteractionType;
43 import org.imsglobal.xsd.imsqti_v2p0.ExtendedTextInteractionType;
44 import org.imsglobal.xsd.imsqti_v2p0.ResponseDeclarationType;
45 import org.imsglobal.xsd.imsqti_v2p0.SimpleChoiceType;
46 import org.telscenter.pas.common.ui.CommonUI;
47 import org.telscenter.pas.common.ui.panel.TextEditorPanel;
48 import org.telscenter.pas.steps.IAssessmentType;
49 import org.telscenter.pas.steps.JaxbQtiStep;
50 import org.telscenter.pas.ui.icons.PasCommonIconProvider;
51 import org.telscenter.pas.ui.util.PasColors;
52
53 import com.jgoodies.binding.beans.BeanAdapter;
54
55 /***
56 * Creates a Text Interaction card
57 *
58 * @author aperritano
59 */
60 public class InteractionCardUI extends AbstractCardUI<BlockInteractionType> {
61
62 protected JTextArea starterAnswerArea;
63
64 protected JTextArea promptArea;
65
66 protected int index = 0;
67
68 protected String[] starterAnswerTypes = { "Small ("+CardConstants.SMALL_ROW+" Rows)",
69 "Medium ("+CardConstants.MEDIUM_ROW+" Rows)", "Large ("+CardConstants.LARGE_ROW+" Rows)" };
70
71 protected JComboBox answerSizeCombo;
72
73 protected JScrollPane starterScroller;
74
75 protected JPanel formPanel;
76
77 protected JButton downButton;
78
79 protected JButton upButton;
80
81 protected AbstractCardContainerUI<BlockInteractionType> interactionCardContainerUI;
82
83 protected ChoiceCardContainerUI cardChoiceContainer;
84
85 protected JButton trashButton;
86
87 protected BeanAdapter beanAdapter;
88
89 protected AssessmentItemType assessmentItem;
90
91 protected JScrollPane promptAreaScroller;
92
93 protected BlockInteractionType interaction;
94
95 private List<ResponseDeclarationType> responseDeclarationList;
96
97 private JaxbQtiStep assmtBean;
98
99 private JRadioButton isInjectedRadio;
100 private JRadioButton isNotInjectedRadio;
101
102 private ButtonGroup startSentenceButtonGroup;
103
104 private UndoManager undoManager;
105
106
107 public InteractionCardUI() {
108 super();
109
110 }
111
112
113
114 /***
115 * Default constructor
116 * @param assmtBean
117 * @param responseDeclarationList
118 *
119 * @param interaction
120 */
121 public InteractionCardUI(JaxbQtiStep assmtBean, BlockInteractionType bi, List<ResponseDeclarationType> responseDeclarationList, UndoManager undoManager) {
122 super();
123 this.assmtBean = assmtBean;
124 this.responseDeclarationList = responseDeclarationList;
125 this.domainObject = bi;
126 this.undoManager = undoManager;
127 init();
128 createMainUI();
129 }
130
131
132 /***
133 * @param bi
134 * @param list
135 * @param beanAdapter
136 */
137 public InteractionCardUI(JaxbQtiStep assmtBean,BlockInteractionType bi, List<ResponseDeclarationType> responseDeclarationList, BeanAdapter beanAdapter, UndoManager undoManager) {
138 super();
139 this.assmtBean = assmtBean;
140 this.domainObject = bi;
141 this.responseDeclarationList = responseDeclarationList;
142 this.undoManager = undoManager;
143 init();
144 createMainUI();
145 this.beanAdapter = beanAdapter;
146 }
147
148
149 protected void init() {
150 this.interaction = (BlockInteractionType) this.domainObject;
151 }
152
153 /***
154 * creates the main layout
155 *
156 * @return
157 */
158 protected JPanel createMainArea() {
159
160 formPanel = new JPanel();
161 formPanel.setLayout(new MigLayout("wrap 2, insets 4"));
162 double pref = TableLayout.PREFERRED;
163 double fill = TableLayout.FILL;
164 double vSpace = 5;
165 double hSpace = 6;
166
167
168
169
170 if (interaction instanceof ExtendedTextInteractionType) {
171 formPanel.add(new JLabel("<html>Open-<br>Response<br>Question:</html>"), "top");
172 formPanel.add(createPromptTextArea());
173 formPanel.add(new JLabel("<html>Response<br>Field Size:</html>"));
174 formPanel.add(createComboPanel());
175 formPanel.add(new JLabel("<html>Starter<br>Sentence:</html>"),"top");
176 formPanel.add(createStarterPanel(),"growx");
177 formPanel.add(new JLabel("<html>Starter<br>Sentence<br>Type:</html>"),"top");
178 formPanel.add(createStarterSentencePanel());
179
180 } else if (interaction instanceof ChoiceInteractionType) {
181 boolean hasCorrectAnswer = ((IAssessmentType)assmtBean).hasCorrectAnswer();
182 String qType = "Survey";
183 if( hasCorrectAnswer) {
184 qType = "Multichoice";
185 }
186
187 formPanel.add(new JLabel("<html>" + qType+"<br>Question:</html>"), "top");
188 formPanel.add(createPromptTextArea());
189
190 formPanel.add(new JLabel("<html>" + qType+"<br>Choices:</html>"));
191
192 StringBuilder sb = new StringBuilder("<html>You can create an unlimited number of choices for your question.");
193 if( hasCorrectAnswer ) {
194 sb.append(" For the correct answer select a radio button.</html>");
195 } else {
196 sb.append("</html>");
197 }
198
199 formPanel.add(new JLabel(sb.toString()));
200 formPanel.add(new JLabel(" "));
201 formPanel.add(createMuliChoicePanel(),"growx");
202 }
203
204 formPanel.setBackground(PasColors.interactionCardFormBackgroundColor);
205 formPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
206
207 return formPanel;
208 }
209
210
211
212
213 /***
214 * @return
215 */
216 protected JPanel createCorrectAnswerComboPanel() {
217 JPanel comboPanel = new JPanel(new BorderLayout(0,0));
218 comboPanel.add(createCorrectAnswerCombo(),BorderLayout.CENTER);
219 JLabel label = new JLabel();
220 label.setIcon(new ImageIcon(PasCommonIconProvider.getImage("help.png")));
221 label.setVerticalAlignment(JLabel.TOP);
222 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>");
223 label.setOpaque(false);
224 label.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
225 comboPanel.add(label,BorderLayout.EAST);
226 comboPanel.setOpaque(false);
227 return comboPanel;
228 }
229
230
231
232 /***
233 * @return
234 */
235 protected JComboBox createCorrectAnswerCombo() {
236
237 return null;
238 }
239
240
241
242 /***
243 * @return
244 */
245 protected JPanel createStarterSentencePanel() {
246 startSentenceButtonGroup = new ButtonGroup();
247
248 isNotInjectedRadio = new JRadioButton("<html>LINK: A link called \"Give me a Starter Sentence\" is displayed to student. If they click the link<br> the starter sentence appears in the Response Field</html>");
249 isNotInjectedRadio.setOpaque(false);
250 isInjectedRadio = new JRadioButton("<html>AUTO: A starter sentence is automatically displayed in the Response Field.</html>");
251 isInjectedRadio.setOpaque(false);
252 isNotInjectedRadio.addActionListener(new ActionListener(){
253
254 public void actionPerformed(ActionEvent e) {
255 JRadioButton source = (JRadioButton)e.getSource();
256 assmtBean.setInjectPrompt( false );
257 }
258
259 });
260 isInjectedRadio.addActionListener(new ActionListener(){
261
262 public void actionPerformed(ActionEvent e) {
263 JRadioButton source = (JRadioButton)e.getSource();
264 assmtBean.setInjectPrompt( true );
265 }});
266 if( assmtBean.isInjectPrompt() ) {
267 isInjectedRadio.setSelected(true);
268 isNotInjectedRadio.setSelected(false);
269 } else {
270 isInjectedRadio.setSelected(false);
271 isNotInjectedRadio.setSelected(true);
272 }
273
274 startSentenceButtonGroup.add(isNotInjectedRadio);
275 startSentenceButtonGroup.add(isInjectedRadio);
276
277 JPanel s = new JPanel(new MigLayout("wrap 1,insets 0"));
278 s.add(isInjectedRadio);
279 s.add(isNotInjectedRadio);
280 s.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
281 s.setOpaque(false);
282 return s;
283 }
284
285
286
287 protected JPanel createStarterPanel() {
288 JPanel starterPanel = new JPanel(new BorderLayout(0,0));
289
290 starterPanel.add(createAnswerStarterArea(),BorderLayout.CENTER);
291 JLabel label = new JLabel();
292 label.setOpaque(false);
293 label.setIcon(new ImageIcon(PasCommonIconProvider.getImage("help.png")));
294 label.setToolTipText("<html>This starter answer guides student writing<br> by suggesting an opening phrase or guiding idea</html>");
295 JPanel t = new JPanel(new BorderLayout(0,0));
296 t.add(label,BorderLayout.NORTH);
297
298 t.setOpaque(false);
299 starterPanel.add(t,BorderLayout.EAST);
300 starterPanel.setOpaque(false);
301
302 return starterPanel;
303 }
304 protected JPanel createComboPanel() {
305 JPanel comboPanel = new JPanel(new BorderLayout(0,0));
306 comboPanel.add(createAnswerCombo(),BorderLayout.CENTER);
307 JLabel label = new JLabel();
308 label.setIcon(new ImageIcon(PasCommonIconProvider.getImage("help.png")));
309 label.setVerticalAlignment(JLabel.TOP);
310 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>");
311 label.setOpaque(false);
312 label.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
313 comboPanel.add(label,BorderLayout.EAST);
314 comboPanel.setOpaque(false);
315 return comboPanel;
316 }
317
318
319 /***
320 * creates the panel where the multi choices are
321 *
322 * @param mcPanel
323 * @return
324 */
325 protected JPanel createMuliChoicePanel() {
326
327 ChoiceInteractionType ci = (ChoiceInteractionType) interaction;
328
329 List<SimpleChoiceType> simpleChoices = ci.getSimpleChoice();
330
331 ResponseDeclarationType rd = findResponseDeclarationForInteraction(ci);
332
333
334 boolean hasCorrectAnswer = ((IAssessmentType)assmtBean).hasCorrectAnswer();
335 if (simpleChoices.isEmpty()) {
336 cardChoiceContainer = new ChoiceCardContainerUI(hasCorrectAnswer,simpleChoices
337 .isEmpty(), ci, rd, undoManager);
338 } else {
339
340 cardChoiceContainer = new ChoiceCardContainerUI(hasCorrectAnswer,false, ci,rd, undoManager);
341 for (SimpleChoiceType simpleChoice : simpleChoices) {
342 ChoiceCardUI cc = new ChoiceCardUI(hasCorrectAnswer,ci,simpleChoice,rd,undoManager);
343 cardChoiceContainer.addChoice(cc);
344 }
345 }
346
347 cardChoiceContainer.setOpaque(false);
348 return cardChoiceContainer;
349 }
350
351
352 /***
353 * This returns the responseDeclaration for an interaction
354 *
355 * @param ci
356 * @return
357 */
358 private ResponseDeclarationType findResponseDeclarationForInteraction(
359 ChoiceInteractionType ci) {
360 for (ResponseDeclarationType rdType : responseDeclarationList) {
361 if( rdType.getIdentifier().equals(ci.getResponseIdentifier())) {
362 return rdType;
363 }
364 }
365 return null;
366 }
367
368 /***
369 * Creating the prompt Panel
370 *
371 * @param promptPanel
372 */
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397 /***
398 * Create prompt text are
399 *
400 * @return
401 */
402 protected JPanel createPromptTextArea() {
403 promptArea = new JTextArea(this.getInteractionPrompt());
404 promptArea.setBackground(PasColors.textEditorPanelTextComponentBackground);
405
406 if( undoManager != null)
407 promptArea.getDocument().addUndoableEditListener(undoManager);
408
409 TextEditorPanel ppanel = new TextEditorPanel(promptArea,new Dimension(CardConstants.TEXT_AREA_LENTH, 125));
410 ppanel.setEditButtonName("Edit HTML");
411 ppanel.setSaveButtonName("Save HTML");
412 JButton jb = ppanel.getEditButton();
413
414 if( jb != null ) {
415 jb.addActionListener(CommonUI.createHTMLTidyEditActionlistener());
416 }
417
418
419
420
421
422
423
424 promptArea.addFocusListener(new FocusListener() {
425
426 public void focusGained(FocusEvent e) {
427
428
429 }
430
431 public void focusLost(FocusEvent e) {
432 JTextArea source = (JTextArea) e.getSource();
433
434 String promptText = source.getText();
435
436
437
438
439 List<Serializable> promptContent = (interaction).getPrompt().getContent();
440 for (Serializable serializable : promptContent) {
441 if (serializable instanceof String) {
442 promptContent.remove(serializable);
443 promptContent.add(promptText);
444 }
445 }
446 }});
447 return ppanel;
448 }
449
450
451
452
453
454 /***
455 * Creates the answer combo
456 * @return
457 */
458 protected JComboBox createAnswerCombo() {
459 answerSizeCombo = new JComboBox(starterAnswerTypes);
460 answerSizeCombo.setOpaque(false);
461
462
463 switch (this.getComboRowType()) {
464 case CardConstants.SMALL_ROW:
465 answerSizeCombo.setSelectedIndex(0);
466 break;
467 case CardConstants.MEDIUM_ROW:
468 answerSizeCombo.setSelectedIndex(1);
469 break;
470 case CardConstants.LARGE_ROW:
471 answerSizeCombo.setSelectedIndex(2);
472 break;
473 default:
474 break;
475 }
476
477 answerSizeCombo.addActionListener(new ActionListener() {
478 public void actionPerformed(ActionEvent e) {
479
480 if (interaction instanceof ExtendedTextInteractionType) {
481
482 JComboBox cb = (JComboBox) e.getSource();
483
484 int selectedIndex = cb.getSelectedIndex();
485 ExtendedTextInteractionType eti = ((ExtendedTextInteractionType) interaction);
486 switch (selectedIndex) {
487 case 0:
488 starterAnswerArea.setRows(CardConstants.SMALL_ROW);
489 eti.setExpectedLines(new BigInteger(CardConstants.SMALL_ROW + ""));
490
491 break;
492 case 1:
493 starterAnswerArea.setRows(CardConstants.MEDIUM_ROW);
494 eti.setExpectedLines(new BigInteger(CardConstants.MEDIUM_ROW+""));
495
496 break;
497 case 2:
498 starterAnswerArea.setRows(CardConstants.LARGE_ROW);
499 eti.setExpectedLines(new BigInteger(CardConstants.LARGE_ROW+""));
500
501 break;
502 default:
503 break;
504 }
505 }
506 }
507
508 });
509 return answerSizeCombo;
510 }
511
512 protected int getComboRowType() {
513
514 if (interaction instanceof ExtendedTextInteractionType) {
515
516 switch (((ExtendedTextInteractionType) interaction).getExpectedLines().intValue()) {
517 case CardConstants.SMALL_ROW:
518 return CardConstants.SMALL_ROW;
519 case CardConstants.MEDIUM_ROW:
520 return CardConstants.MEDIUM_ROW;
521 case CardConstants.LARGE_ROW:
522 return CardConstants.LARGE_ROW;
523 default:
524 return CardConstants.SMALL_ROW;
525 }
526 }
527
528 return CardConstants.SMALL_ROW;
529 }
530
531 /***
532 * Get the Interaction Prompt
533 *
534 * @return
535 */
536 protected String getInteractionPrompt() {
537
538 List<Serializable> promptContent = interaction.getPrompt().getContent();
539 for (Serializable serializable : promptContent) {
540 if (serializable instanceof String) {
541 return (String) serializable;
542 }
543 }
544
545
546 return "";
547 }
548
549 /***
550 * Gets the starter answer for interactions that have starter answers
551 *
552 * @return
553 */
554 protected String getInteractionStarterAnswer() {
555 String placeholderText = ((ExtendedTextInteractionType) interaction)
556 .getPlaceholderText();
557
558 if (placeholderText == null)
559 return "";
560
561 return placeholderText;
562 }
563
564 /***
565 * Refresh
566 */
567 protected void refreshFormPanel() {
568 starterAnswerArea.revalidate();
569
570 formPanel.revalidate();
571 }
572
573 /***
574 * Creates the starter answer panel
575 *
576 * @param starterAnswerPanel
577 */
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599 /***
600 * @return
601 *
602 */
603 protected JScrollPane createAnswerStarterArea() {
604 starterAnswerArea = new JTextArea();
605
606
607
608 starterAnswerArea.setRows(6);
609 starterAnswerArea.setText(this.getInteractionStarterAnswer());
610 starterAnswerArea.setEditable(true);
611 if( undoManager != null)
612 starterAnswerArea.getDocument().addUndoableEditListener(undoManager);
613
614 this.modTextArea(starterAnswerArea);
615
616 starterAnswerArea.addFocusListener(new FocusListener() {
617
618 public void focusGained(FocusEvent e) {
619
620
621 }
622
623 public void focusLost(FocusEvent e) {
624 JTextArea source = (JTextArea) e.getSource();
625
626
627
628
629
630
631 String starterAnswerAreaText = source.getText();
632
633 ((ExtendedTextInteractionType) interaction)
634 .setPlaceholderText(starterAnswerAreaText);
635
636
637
638 }});
639
640
641 JScrollPane scroller = new JScrollPane(starterAnswerArea);
642 scroller.setPreferredSize(new Dimension(CardConstants.TEXT_AREA_LENTH,starterAnswerArea.getPreferredSize().height));
643 this.modScrollArea(scroller);
644 return scroller;
645
646 }
647
648 /***
649 * Get the interaction
650 *
651 * @return
652 */
653 public BlockInteractionType getInteraction() {
654 return (BlockInteractionType) this.domainObject;
655 }
656
657 /***
658 * set the interaction
659 *
660 * @param interaction
661 */
662 public void setInteraction(BlockInteractionType interaction) {
663 this.domainObject = interaction;
664 }
665
666 /***
667 * @param assessmentItem
668 */
669 public void setAssessmentItem(AssessmentItemType assessmentItem) {
670 this.assessmentItem = assessmentItem;
671 }
672
673 /***
674 * Test
675 *
676 * @param args
677 */
678 public static void main(String[] args) {
679 JFrame frame = new JFrame("note card test");
680
681 Container contentPane = frame.getContentPane();
682
683 JButton showButton = new JButton("show ui");
684
685 showButton.addActionListener(new ActionListener() {
686
687 public void actionPerformed(ActionEvent e) {
688
689 JFrame frame = new JFrame("note card test");
690
691 Container contentPane = frame.getContentPane();
692 InteractionCardUI noteUI = new InteractionCardUI();
693 contentPane.add(noteUI);
694 frame.setSize(noteUI.getPreferredSize());
695 frame.setVisible(true);
696 }
697
698 });
699 contentPane.add(showButton);
700
701 frame.setSize(200, 200);
702 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
703 frame.setVisible(true);
704 }
705
706 }