151 return pathList.getNextVisible();
152 }
153
154 Question getPrevVisible() {
155 return pathList.getPrevVisible();
156 }
157
158 Question getLastVisible() {
159 return pathList.getLastVisible();
160 }
161
162 JMenu getMarkerMenu() {
163 return createMenu();
164 }
165
166 private void initGUI() {
167 setName("path");
168 setFocusable(false);
169 setLayout(new BorderLayout());
170 pathList = new PathList();
171 list = new JList(pathList);
172 setInfo(list, "path.list", true);
173 list.setCellRenderer(pathList);
174 KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
175 list.registerKeyboardAction(pathList, enterKey, JComponent.WHEN_FOCUSED);
176 list.addListSelectionListener(pathList);
177 list.addMouseListener(pathList);
178 //list.setPrototypeCellValue("What is a good default to use?");
179
180 // would be better if this were configurable
181 list.setFixedCellWidth(2 * DOTS_PER_INCH);
182
183 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
184 list.setBackground(new Color(255, 255, 255, 0));
185 list.setOpaque(false);
186 list.setVisibleRowCount(5);
187 list.setTransferHandler(new TransferHandler() {
188 @Override
189 public int getSourceActions(JComponent c) {
190 return COPY;
191 }
227 else
228 ac.setAccessibleDescription(i18n.getString(uiKey + ".desc"));
229 }
230
231 private QuestionPanel questionPanel;
232 private Interview interview;
233 private PathList pathList;
234 private JList<Object> list;
235 private String moreText;
236
237 // client parameters
238 private boolean markersEnabled;
239 private boolean markersFilterEnabled;
240 private String markerName = null; // theoretically settable
241
242 private static final I18NResourceBundle i18n = I18NResourceBundle.getDefaultBundle();
243 private static Color INVALID_VALUE_COLOR = i18n.getErrorColor();
244 private static final int DOTS_PER_INCH = Toolkit.getDefaultToolkit().getScreenResolution();
245
246 private class PathList
247 extends AbstractListModel
248 implements ActionListener, AncestorListener,
249 ListCellRenderer, ListSelectionListener,
250 MouseListener,
251 Interview.Observer
252 {
253 //----- navigation support for WizPane -----------------------
254
255 Question getNextVisible() {
256 for (int i = currIndex + 1; i < currEntries.length; i++) {
257 Object e = currEntries[i];
258 if (e instanceof Question)
259 return ((Question) e);
260 }
261 return null;
262 }
263
264 Question getPrevVisible() {
265 for (int i = currIndex - 1; i >= 0; i--) {
266 Object e = currEntries[i];
267 if (e instanceof Question)
268 return ((Question) e);
269 }
270 return null;
271 }
272
273 Question getLastVisible() {
274 for (int i = currEntries.length - 1; i >= 0; i--) {
275 Object e = currEntries[i];
276 if (e instanceof Question)
277 return ((Question) e);
278 }
279 return null;
280 }
281
282 //----- state support for menus -----------------------------
283
284 boolean isQuestionVisible(Question q) {
285 for (Object e : currEntries) {
286 if (e instanceof Question && e == q)
287 return true;
288 else if (e instanceof List && ((List) e).contains(q))
289 return false;
290 }
291 return false;
292 }
293
294 boolean isQuestionAutoOpened(Question q) {
295 // only return true if the preceding marked question is in the autoOpen set
296 boolean autoOpened = autoOpenSet.contains(null);
297 for (int i = 0; i < currEntries.length; i++) {
298 Object e = currEntries[i];
299 if (e instanceof Question) {
300 Question qe = (Question) e;
301 if (qe.hasMarker(markerName)) {
302 if (qe == q)
303 return false;
304 autoOpened = autoOpenSet.contains(qe);
305 }
306 else if (qe == q)
307 return autoOpened;
308 }
309 else if (e instanceof List && ((List) e).contains(q))
310 return false;
311 }
312 return false;
313 }
314
315 //----- actions ------------------------
316
317 void markCurrentQuestion() {
318 setQuestionMarked(interview.getCurrentQuestion(), true);
319 }
320
321 void unmarkCurrentQuestion() {
322 setQuestionMarked(interview.getCurrentQuestion(), false);
323 }
324
325 private void setQuestionMarked(Question q, boolean on) {
326 questionPanel.saveCurrentResponse();
327 if (on)
328 q.addMarker(markerName);
329 else
391 }
392
393 //----- from AbstractListModel -----------
394
395 public int getSize() {
396 return (currEntries == null ? 0 : currEntries.length);
397 }
398
399 public Object getElementAt(int index) {
400 return (index < currEntries.length ? currEntries[index] : null);
401 }
402
403 //----- from ListCellRenderer -----------
404
405 private JLabel sample = new JLabel() {
406 public Dimension getMaximumSize() {
407 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
408 }
409 };
410
411 public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus) {
412 if (o instanceof Question) {
413 Question q = (Question)o;
414 Font f;
415 String s;
416 Color c;
417 Color bg = null; // null is default
418 if (q instanceof ErrorQuestion) {
419 f = list.getFont().deriveFont(Font.BOLD);
420 s = " " + q.getSummary();
421 c = INVALID_VALUE_COLOR;
422 }
423 else if (q instanceof NullQuestion) {
424 int level = ((NullQuestion)q).getLevel();
425
426 switch (level) {
427 case NullQuestion.LEVEL_NONE:
428 f = list.getFont();
429 s = " " + q.getSummary();
430 c = list.getForeground();
431 bg = null;
491 if (isSelected) {
492 sample.setBackground(list.getSelectionBackground());
493 //sample.setForeground(list.getSelectionForeground());
494 }
495 else {
496 //sample.setBackground(list.getBackground());
497 //sample.setForeground(list.getForeground());
498 }
499 sample.setOpaque(true);
500 sample.setEnabled(list.isEnabled());
501 sample.setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : null);
502
503 return sample;
504 }
505
506 //----- from ActionListener -----------
507
508 // invoked by keyboard "enter"
509 public void actionPerformed(ActionEvent e) {
510 //System.err.println("PP.actionPerformed");
511 JList list = (JList)(e.getSource());
512 Object o = list.getSelectedValue();
513 if (o != null && o instanceof Question) {
514 Question q = (Question)o;
515 if (q == interview.getCurrentQuestion())
516 return;
517
518 //System.err.println("PP.actionPerformed saveCurrentResponse");
519 questionPanel.saveCurrentResponse();
520
521 try {
522 //System.err.println("PP.actionPerformed setCurrentQuestion");
523 interview.setCurrentQuestion(q);
524 }
525 catch (Interview.Fault ex) {
526 // ignore, should never happen; FLW
527 }
528 }
529 }
530
531 //----- from ListSelectionListener -----------
532
533 // invoked by mouse selection (or by list.setSelectedXXX ??)
534 public void valueChanged(ListSelectionEvent e) {
535 JList list = (JList) (e.getSource());
536 Object o = list.getSelectedValue();
537 if (o == null)
538 return;
539
540 // make sure the interview's current question is synchronized with
541 // the list selection
542 if (o instanceof Question) {
543 Question q = (Question) o;
544 if (q == interview.getCurrentQuestion())
545 return;
546
547 questionPanel.saveCurrentResponse();
548
549 try {
550 interview.setCurrentQuestion(q);
551 }
552 catch (Interview.Fault ex) {
553 // ignore, should never happen; FLW
554 }
555 }
556 else if (o instanceof List) {
557 List l = (List) o;
558 if (l.contains(interview.getCurrentQuestion()))
559 return;
560
561 questionPanel.saveCurrentResponse();
562
563 try {
564 Question q = (Question) (l.get(0));
565 interview.setCurrentQuestion(q);
566 }
567 catch (Interview.Fault ex) {
568 // ignore, should never happen; FLW
569 }
570
571 }
572 else {
573 // if the user tries to select the More string,
574 // reject the request by resetting to the currIndex
575 list.setSelectedIndex(currIndex);
576 }
577 }
589 interview.removeObserver(this);
590 }
591
592 //----- from MouseListener -----------
593
594 public void mouseEntered(MouseEvent e) { }
595
596 public void mouseExited(MouseEvent e) { }
597
598 public void mousePressed(MouseEvent e) {
599 if (markersEnabled && e.isPopupTrigger() && isOverSelection(e))
600 showPopupMenu(e);
601 }
602
603 public void mouseReleased(MouseEvent e) {
604 if (markersEnabled && e.isPopupTrigger() && isOverSelection(e))
605 showPopupMenu(e);
606 }
607
608 private boolean isOverSelection(MouseEvent e) {
609 JList l = (JList) (e.getComponent());
610 Rectangle r = l.getCellBounds(currIndex, currIndex);
611 return (r.contains(e.getX(), e.getY()));
612 }
613
614 private void showPopupMenu(MouseEvent e) {
615 if (popupMenu == null)
616 popupMenu = createPopupMenu();
617 popupMenu.show(e.getComponent(), e.getX(), e.getY());
618 }
619
620 public void mouseClicked(MouseEvent e) {
621 if (!markersEnabled)
622 return;
623
624 Point p = e.getPoint();
625 int index = list.locationToIndex(p);
626 if (index == -1)
627 return;
628 Object entry = currEntries[index];
629
642 if (entry instanceof List)
643 openEntry(index);
644 else
645 closeEntry(index);
646 }
647 break;
648 }
649 }
650
651 //----- from Interview.Observer -----------
652
653 public void pathUpdated() {
654 update(interview.getPath(), interview.getCurrentQuestion());
655 }
656
657 public void currentQuestionChanged(Question q) {
658 int prevIndex = currIndex;
659 currQuestion = q;
660 for (int i = 0; i < currEntries.length; i++) {
661 Object o = currEntries[i];
662 if (o == q || (o instanceof List && ((List) o).contains(q))) {
663 currIndex = i;
664 break;
665 }
666 }
667 fireContentsChanged(this, prevIndex, currIndex);
668
669 list.setSelectedIndex(currIndex);
670 list.ensureIndexIsVisible(currIndex);
671 }
672
673 public void finished() {
674 }
675
676 void update() {
677 update(currPath, currQuestion);
678 }
679
680 void update(Question q) {
681 if (markersFilterEnabled)
682 update();
737 if (firstDiff != oldEntries.length || firstDiff != newEntries.length) {
738 if (firstDiff != shorterEntriesLength) {
739 //System.err.println("PP.update: change[" + firstDiff + "," + (shorterEntriesLength-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
740 fireContentsChanged(this, firstDiff, shorterEntriesLength-1);
741 }
742
743 if (shorterEntriesLength != oldEntries.length) {
744 //System.err.println("PP.update: remove[" + shorterEntriesLength + "," + (oldEntries.length-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
745 fireIntervalRemoved(this, shorterEntriesLength, oldEntries.length-1);
746 }
747 if (shorterEntriesLength != newEntries.length) {
748 //System.err.println("PP.update: add[" + shorterEntriesLength + "," + (newEntries.length-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
749 fireIntervalAdded(this, shorterEntriesLength, newEntries.length-1);
750 }
751 }
752
753 currQuestion = newCurrQuestion;
754 for (int i = 0; i < currEntries.length; i++) {
755 Object o = currEntries[i];
756 if (o == currQuestion
757 || (o instanceof List && ((List) o).contains(currQuestion))) {
758 currIndex = i;
759 break;
760 }
761 }
762
763 list.setSelectedIndex(currIndex);
764 list.ensureIndexIsVisible(currIndex);
765 //System.err.println("PP.update: sel:" + currIndex + " " + currQuestion);
766 }
767
768 private Object[] getEntries(Question[] path) {
769 if (path.length == 0) // transient startup condition
770 return path;
771
772 Question last = path[path.length - 1];
773 boolean needMore = !(last instanceof ErrorQuestion || last instanceof FinalQuestion);
774 // quick check to see if we can simply use the path as is
775 if ( (!markersEnabled || !markersFilterEnabled) && !needMore)
776 return path;
777
789 v.add(q);
790 }
791 else if (autoOpenSet.contains(lastMarker)) {
792 v.add(q);
793 }
794 else {
795 List<Question> l;
796 Object o = v.lastElement();
797 if (o == null || o instanceof Question) {
798 l = new Vector<>();
799 v.add(l);
800 }
801 else
802 l = (List<Question>) o;
803 l.add(q);
804 }
805 }
806
807 // auto-expand the final section if it doesn't end in FinalQuestion
808 if (!(last instanceof FinalQuestion) && v.lastElement() instanceof List) {
809 List l = (List) (v.lastElement());
810 v.setSize(v.size() - 1);
811 v.addAll(l);
812 }
813
814 if (needMore)
815 v.add(moreText);
816
817 Object[] a = new Object[v.size()];
818 v.copyInto(a);
819 return a;
820 }
821
822
823
824 // currPath and currQuestion give info as obtained from the interview
825 private Question[] currPath = new Question[0];
826 private Question currQuestion;
827
828 // currEntries and currIndex give displayable entries
829 // entries may be Question, List<Question>, or String
|
151 return pathList.getNextVisible();
152 }
153
154 Question getPrevVisible() {
155 return pathList.getPrevVisible();
156 }
157
158 Question getLastVisible() {
159 return pathList.getLastVisible();
160 }
161
162 JMenu getMarkerMenu() {
163 return createMenu();
164 }
165
166 private void initGUI() {
167 setName("path");
168 setFocusable(false);
169 setLayout(new BorderLayout());
170 pathList = new PathList();
171 list = new JList<>(pathList);
172 setInfo(list, "path.list", true);
173 list.setCellRenderer(pathList);
174 KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
175 list.registerKeyboardAction(pathList, enterKey, JComponent.WHEN_FOCUSED);
176 list.addListSelectionListener(pathList);
177 list.addMouseListener(pathList);
178 //list.setPrototypeCellValue("What is a good default to use?");
179
180 // would be better if this were configurable
181 list.setFixedCellWidth(2 * DOTS_PER_INCH);
182
183 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
184 list.setBackground(new Color(255, 255, 255, 0));
185 list.setOpaque(false);
186 list.setVisibleRowCount(5);
187 list.setTransferHandler(new TransferHandler() {
188 @Override
189 public int getSourceActions(JComponent c) {
190 return COPY;
191 }
227 else
228 ac.setAccessibleDescription(i18n.getString(uiKey + ".desc"));
229 }
230
231 private QuestionPanel questionPanel;
232 private Interview interview;
233 private PathList pathList;
234 private JList<Object> list;
235 private String moreText;
236
237 // client parameters
238 private boolean markersEnabled;
239 private boolean markersFilterEnabled;
240 private String markerName = null; // theoretically settable
241
242 private static final I18NResourceBundle i18n = I18NResourceBundle.getDefaultBundle();
243 private static Color INVALID_VALUE_COLOR = i18n.getErrorColor();
244 private static final int DOTS_PER_INCH = Toolkit.getDefaultToolkit().getScreenResolution();
245
246 private class PathList
247 extends AbstractListModel<Object>
248 implements ActionListener, AncestorListener,
249 ListCellRenderer<Object>, ListSelectionListener,
250 MouseListener,
251 Interview.Observer
252 {
253 //----- navigation support for WizPane -----------------------
254
255 Question getNextVisible() {
256 for (int i = currIndex + 1; i < currEntries.length; i++) {
257 Object e = currEntries[i];
258 if (e instanceof Question)
259 return ((Question) e);
260 }
261 return null;
262 }
263
264 Question getPrevVisible() {
265 for (int i = currIndex - 1; i >= 0; i--) {
266 Object e = currEntries[i];
267 if (e instanceof Question)
268 return ((Question) e);
269 }
270 return null;
271 }
272
273 Question getLastVisible() {
274 for (int i = currEntries.length - 1; i >= 0; i--) {
275 Object e = currEntries[i];
276 if (e instanceof Question)
277 return ((Question) e);
278 }
279 return null;
280 }
281
282 //----- state support for menus -----------------------------
283
284 boolean isQuestionVisible(Question q) {
285 for (Object e : currEntries) {
286 if (e instanceof Question && e == q)
287 return true;
288 else if (e instanceof List && ((List<?>) e).contains(q))
289 return false;
290 }
291 return false;
292 }
293
294 boolean isQuestionAutoOpened(Question q) {
295 // only return true if the preceding marked question is in the autoOpen set
296 boolean autoOpened = autoOpenSet.contains(null);
297 for (int i = 0; i < currEntries.length; i++) {
298 Object e = currEntries[i];
299 if (e instanceof Question) {
300 Question qe = (Question) e;
301 if (qe.hasMarker(markerName)) {
302 if (qe == q)
303 return false;
304 autoOpened = autoOpenSet.contains(qe);
305 }
306 else if (qe == q)
307 return autoOpened;
308 }
309 else if (e instanceof List && ((List<?>) e).contains(q))
310 return false;
311 }
312 return false;
313 }
314
315 //----- actions ------------------------
316
317 void markCurrentQuestion() {
318 setQuestionMarked(interview.getCurrentQuestion(), true);
319 }
320
321 void unmarkCurrentQuestion() {
322 setQuestionMarked(interview.getCurrentQuestion(), false);
323 }
324
325 private void setQuestionMarked(Question q, boolean on) {
326 questionPanel.saveCurrentResponse();
327 if (on)
328 q.addMarker(markerName);
329 else
391 }
392
393 //----- from AbstractListModel -----------
394
395 public int getSize() {
396 return (currEntries == null ? 0 : currEntries.length);
397 }
398
399 public Object getElementAt(int index) {
400 return (index < currEntries.length ? currEntries[index] : null);
401 }
402
403 //----- from ListCellRenderer -----------
404
405 private JLabel sample = new JLabel() {
406 public Dimension getMaximumSize() {
407 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
408 }
409 };
410
411 public Component getListCellRendererComponent(JList<?> list, Object o, int index, boolean isSelected, boolean cellHasFocus) {
412 if (o instanceof Question) {
413 Question q = (Question)o;
414 Font f;
415 String s;
416 Color c;
417 Color bg = null; // null is default
418 if (q instanceof ErrorQuestion) {
419 f = list.getFont().deriveFont(Font.BOLD);
420 s = " " + q.getSummary();
421 c = INVALID_VALUE_COLOR;
422 }
423 else if (q instanceof NullQuestion) {
424 int level = ((NullQuestion)q).getLevel();
425
426 switch (level) {
427 case NullQuestion.LEVEL_NONE:
428 f = list.getFont();
429 s = " " + q.getSummary();
430 c = list.getForeground();
431 bg = null;
491 if (isSelected) {
492 sample.setBackground(list.getSelectionBackground());
493 //sample.setForeground(list.getSelectionForeground());
494 }
495 else {
496 //sample.setBackground(list.getBackground());
497 //sample.setForeground(list.getForeground());
498 }
499 sample.setOpaque(true);
500 sample.setEnabled(list.isEnabled());
501 sample.setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : null);
502
503 return sample;
504 }
505
506 //----- from ActionListener -----------
507
508 // invoked by keyboard "enter"
509 public void actionPerformed(ActionEvent e) {
510 //System.err.println("PP.actionPerformed");
511 JList<?> list = (JList<?>)(e.getSource());
512 Object o = list.getSelectedValue();
513 if (o != null && o instanceof Question) {
514 Question q = (Question)o;
515 if (q == interview.getCurrentQuestion())
516 return;
517
518 //System.err.println("PP.actionPerformed saveCurrentResponse");
519 questionPanel.saveCurrentResponse();
520
521 try {
522 //System.err.println("PP.actionPerformed setCurrentQuestion");
523 interview.setCurrentQuestion(q);
524 }
525 catch (Interview.Fault ex) {
526 // ignore, should never happen; FLW
527 }
528 }
529 }
530
531 //----- from ListSelectionListener -----------
532
533 // invoked by mouse selection (or by list.setSelectedXXX ??)
534 public void valueChanged(ListSelectionEvent e) {
535 JList<?> list = (JList<?>) (e.getSource());
536 Object o = list.getSelectedValue();
537 if (o == null)
538 return;
539
540 // make sure the interview's current question is synchronized with
541 // the list selection
542 if (o instanceof Question) {
543 Question q = (Question) o;
544 if (q == interview.getCurrentQuestion())
545 return;
546
547 questionPanel.saveCurrentResponse();
548
549 try {
550 interview.setCurrentQuestion(q);
551 }
552 catch (Interview.Fault ex) {
553 // ignore, should never happen; FLW
554 }
555 }
556 else if (o instanceof List) {
557 List<?> l = (List<?>) o;
558 if (l.contains(interview.getCurrentQuestion()))
559 return;
560
561 questionPanel.saveCurrentResponse();
562
563 try {
564 Question q = (Question) (l.get(0));
565 interview.setCurrentQuestion(q);
566 }
567 catch (Interview.Fault ex) {
568 // ignore, should never happen; FLW
569 }
570
571 }
572 else {
573 // if the user tries to select the More string,
574 // reject the request by resetting to the currIndex
575 list.setSelectedIndex(currIndex);
576 }
577 }
589 interview.removeObserver(this);
590 }
591
592 //----- from MouseListener -----------
593
594 public void mouseEntered(MouseEvent e) { }
595
596 public void mouseExited(MouseEvent e) { }
597
598 public void mousePressed(MouseEvent e) {
599 if (markersEnabled && e.isPopupTrigger() && isOverSelection(e))
600 showPopupMenu(e);
601 }
602
603 public void mouseReleased(MouseEvent e) {
604 if (markersEnabled && e.isPopupTrigger() && isOverSelection(e))
605 showPopupMenu(e);
606 }
607
608 private boolean isOverSelection(MouseEvent e) {
609 JList<?> l = (JList<?>) (e.getComponent());
610 Rectangle r = l.getCellBounds(currIndex, currIndex);
611 return (r.contains(e.getX(), e.getY()));
612 }
613
614 private void showPopupMenu(MouseEvent e) {
615 if (popupMenu == null)
616 popupMenu = createPopupMenu();
617 popupMenu.show(e.getComponent(), e.getX(), e.getY());
618 }
619
620 public void mouseClicked(MouseEvent e) {
621 if (!markersEnabled)
622 return;
623
624 Point p = e.getPoint();
625 int index = list.locationToIndex(p);
626 if (index == -1)
627 return;
628 Object entry = currEntries[index];
629
642 if (entry instanceof List)
643 openEntry(index);
644 else
645 closeEntry(index);
646 }
647 break;
648 }
649 }
650
651 //----- from Interview.Observer -----------
652
653 public void pathUpdated() {
654 update(interview.getPath(), interview.getCurrentQuestion());
655 }
656
657 public void currentQuestionChanged(Question q) {
658 int prevIndex = currIndex;
659 currQuestion = q;
660 for (int i = 0; i < currEntries.length; i++) {
661 Object o = currEntries[i];
662 if (o == q || (o instanceof List && ((List<?>) o).contains(q))) {
663 currIndex = i;
664 break;
665 }
666 }
667 fireContentsChanged(this, prevIndex, currIndex);
668
669 list.setSelectedIndex(currIndex);
670 list.ensureIndexIsVisible(currIndex);
671 }
672
673 public void finished() {
674 }
675
676 void update() {
677 update(currPath, currQuestion);
678 }
679
680 void update(Question q) {
681 if (markersFilterEnabled)
682 update();
737 if (firstDiff != oldEntries.length || firstDiff != newEntries.length) {
738 if (firstDiff != shorterEntriesLength) {
739 //System.err.println("PP.update: change[" + firstDiff + "," + (shorterEntriesLength-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
740 fireContentsChanged(this, firstDiff, shorterEntriesLength-1);
741 }
742
743 if (shorterEntriesLength != oldEntries.length) {
744 //System.err.println("PP.update: remove[" + shorterEntriesLength + "," + (oldEntries.length-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
745 fireIntervalRemoved(this, shorterEntriesLength, oldEntries.length-1);
746 }
747 if (shorterEntriesLength != newEntries.length) {
748 //System.err.println("PP.update: add[" + shorterEntriesLength + "," + (newEntries.length-1) + "/" + oldEntries.length + "," + newEntries.length + "]" + interview);
749 fireIntervalAdded(this, shorterEntriesLength, newEntries.length-1);
750 }
751 }
752
753 currQuestion = newCurrQuestion;
754 for (int i = 0; i < currEntries.length; i++) {
755 Object o = currEntries[i];
756 if (o == currQuestion
757 || (o instanceof List && ((List<?>) o).contains(currQuestion))) {
758 currIndex = i;
759 break;
760 }
761 }
762
763 list.setSelectedIndex(currIndex);
764 list.ensureIndexIsVisible(currIndex);
765 //System.err.println("PP.update: sel:" + currIndex + " " + currQuestion);
766 }
767
768 private Object[] getEntries(Question[] path) {
769 if (path.length == 0) // transient startup condition
770 return path;
771
772 Question last = path[path.length - 1];
773 boolean needMore = !(last instanceof ErrorQuestion || last instanceof FinalQuestion);
774 // quick check to see if we can simply use the path as is
775 if ( (!markersEnabled || !markersFilterEnabled) && !needMore)
776 return path;
777
789 v.add(q);
790 }
791 else if (autoOpenSet.contains(lastMarker)) {
792 v.add(q);
793 }
794 else {
795 List<Question> l;
796 Object o = v.lastElement();
797 if (o == null || o instanceof Question) {
798 l = new Vector<>();
799 v.add(l);
800 }
801 else
802 l = (List<Question>) o;
803 l.add(q);
804 }
805 }
806
807 // auto-expand the final section if it doesn't end in FinalQuestion
808 if (!(last instanceof FinalQuestion) && v.lastElement() instanceof List) {
809 List<?> l = (List<?>) (v.lastElement());
810 v.setSize(v.size() - 1);
811 v.addAll(l);
812 }
813
814 if (needMore)
815 v.add(moreText);
816
817 Object[] a = new Object[v.size()];
818 v.copyInto(a);
819 return a;
820 }
821
822
823
824 // currPath and currQuestion give info as obtained from the interview
825 private Question[] currPath = new Question[0];
826 private Question currQuestion;
827
828 // currEntries and currIndex give displayable entries
829 // entries may be Question, List<Question>, or String
|