private String getRepetitionText(String type, FormIndex index, boolean newrep) { if (element instanceof GroupDef && ((GroupDef) element).getRepeat() && index.getElementMultiplicity() >= 0) { GroupDef g = (GroupDef) element; String title = getLongText(); int ix = index.getElementMultiplicity() + 1; int count = getNumRepetitions(); String caption = null; if ("header".equals(type)) { caption = g.entryHeader; } else if ("choose".equals(type)) { caption = g.chooseCaption; if (caption == null) { caption = g.entryHeader; } } if (caption == null) { return title + " " + ix + "/" + count; } HashMap<String, Object> vars = new HashMap<String, Object>(); vars.put("name", title); vars.put("i", Integer.valueOf(ix)); vars.put("n", Integer.valueOf(count)); vars.put("new", new Boolean(newrep)); return form.fillTemplateString(caption, index.getReference(), vars); } else { return null; } }
public boolean equals(Object o) { if (!(o instanceof FormIndex)) return false; FormIndex a = this; FormIndex b = (FormIndex) o; return (a.compareTo(b) == 0); // //TODO: while(true) loops freak me out, this should probably // //get written more safely. -ctsims // // //Iterate over each level of reference, and identify whether // //each object stays in sync // while(true) { // if(index.isTerminal() != local.isTerminal() || // index.getLocalIndex() != local.getLocalIndex() || // index.getInstanceIndex() != local.getInstanceIndex()) { // return false; // } // if(index.isTerminal()) { // return true; // } // local = local.getNextLevel(); // index = index.getNextLevel(); // } // }
public IFormElement getChild(FormIndex index) { IFormElement element = this; while (index != null && index.isInForm()) { element = element.getChild(index.getLocalIndex()); index = index.getNextLevel(); } return element; }
public String toString() { String ret = ""; FormIndex ref = this; while (ref != null) { ret += ref.getLocalIndex(); ret += ref.getInstanceIndex() == -1 ? ", " : "_" + ref.getInstanceIndex() + ", "; ref = ref.nextLevel; } return ret; }
/** * Trims any negative indices from the end of the passed in index. * * @param index * @return */ public static FormIndex trimNegativeIndices(FormIndex index) { if (!index.isTerminal()) { return new FormIndex(trimNegativeIndices(index.nextLevel), index); } else { if (index.getLocalIndex() < 0) { return null; } else { return index; } } }
/** * Takes in a form index which is a subset of this index, and returns the total difference between * them. This is useful for stepping up the level of index specificty. If the subIndex is not a * valid subIndex of this index, null is returned. Since the FormIndex represented by null is * always a subset, if null is passed in as a subIndex, the full index is returned * * <p>For example: Indices a = 1_0,2,1,3 b = 1,3 * * <p>a.diff(b) = 1_0,2 * * @param subIndex * @return */ public FormIndex diff(FormIndex subIndex) { if (subIndex == null) { return this; } if (!isSubIndex(this, subIndex)) { return null; } if (subIndex.equals(this)) { return null; } return new FormIndex(nextLevel.diff(subIndex), this.snip()); }
/** * Constructs an index which references an element past the level of specificity of the current * context, founded by the currentLevel index. (currentLevel, (nextLevel...)) */ public FormIndex(FormIndex nextLevel, FormIndex currentLevel) { if (currentLevel == null) { this.nextLevel = nextLevel.nextLevel; this.localIndex = nextLevel.localIndex; this.instanceIndex = nextLevel.instanceIndex; this.reference = nextLevel.reference; } else { this.nextLevel = nextLevel; this.localIndex = currentLevel.getLocalIndex(); this.instanceIndex = currentLevel.getInstanceIndex(); this.reference = currentLevel.reference; } }
public boolean canCreateRepeat(TreeReference repeatRef, FormIndex repeatIndex) { GroupDef repeat = (GroupDef) this.getChild(repeatIndex); // Check to see if this repeat can have children added by the user if (repeat.noAddRemove) { // Check to see if there's a count to use to determine how many children this repeat // should have if (repeat.getCountReference() != null) { int currentMultiplicity = repeatIndex.getElementMultiplicity(); // get the total multiplicity possible long fullcount = ((Integer) this.getInstance().getDataValue(repeat.getCountReference()).getValue()) .intValue(); if (fullcount <= currentMultiplicity) { return false; } } else { // Otherwise the user can never add repeat instances return false; } } // TODO: If we think the node is still relevant, we also need to figure out a way to test that // assumption against // the repeat's constraints. return true; }
// TODO: this is explicitly missing integration with the new multi-media support // TODO: localize the default captions public String getRepeatText(String typeKey) { GroupDef g = (GroupDef) element; if (!g.getRepeat()) { throw new RuntimeException("not a repeat"); } String title = getLongText(); int count = getNumRepetitions(); String caption = null; if ("mainheader".equals(typeKey)) { caption = g.mainHeader; if (caption == null) { return title; } } else if ("add".equals(typeKey)) { caption = g.addCaption; if (caption == null) { return "Add another " + title; } } else if ("add-empty".equals(typeKey)) { caption = g.addEmptyCaption; if (caption == null) { caption = g.addCaption; } if (caption == null) { return "None - Add " + title; } } else if ("del".equals(typeKey)) { caption = g.delCaption; if (caption == null) { return "Delete " + title; } } else if ("done".equals(typeKey)) { caption = g.doneCaption; if (caption == null) { return "Done"; } } else if ("done-empty".equals(typeKey)) { caption = g.doneEmptyCaption; if (caption == null) { caption = g.doneCaption; } if (caption == null) { return "Skip"; } } else if ("delheader".equals(typeKey)) { caption = g.delHeader; if (caption == null) { return "Delete which " + title + "?"; } } HashMap<String, Object> vars = new HashMap<String, Object>(); vars.put("name", title); vars.put("n", Integer.valueOf(count)); return form.fillTemplateString(caption, index.getReference(), vars); }
public void collapseIndex( FormIndex index, Vector indexes, Vector multiplicities, Vector elements) { if (!index.isInForm()) { return; } IFormElement element = this; while (index != null) { int i = index.getLocalIndex(); element = element.getChild(i); indexes.addElement(new Integer(i)); multiplicities.addElement( new Integer(index.getInstanceIndex() == -1 ? 0 : index.getInstanceIndex())); elements.addElement(element); index = index.getNextLevel(); } }
public static boolean isSubIndex(FormIndex parent, FormIndex child) { if (child.equals(parent)) { return true; } else { if (parent == null) { return false; } return isSubIndex(parent.nextLevel, child); } }
// if exact = true: return the index of a value, -1 if not present // if exact = false: return the index of the highest value <= the target value, -1 if all values // are greater than the target value public int indexOf(FormIndex index, boolean exact) { int lo = 0; int hi = v.size() - 1; while (lo <= hi) { int mid = (lo + hi) / 2; FormIndex val = get(mid); if (val.compareTo(index) < 0) { lo = mid + 1; } else if (val.compareTo(index) > 0) { hi = mid - 1; } else { return mid; } } return exact ? -1 : lo - 1; }
public int getNumRepetitions(FormIndex index) { Vector indexes = new Vector(); Vector multiplicities = new Vector(); Vector elements = new Vector(); if (!index.isInForm()) { throw new RuntimeException("not an in-form index"); } collapseIndex(index, indexes, multiplicities, elements); if (!(elements.lastElement() instanceof GroupDef) || !((GroupDef) elements.lastElement()).getRepeat()) { throw new RuntimeException("current element not a repeat"); } // so painful TreeElement templNode = instance.getTemplate(index.getReference()); TreeReference parentPath = templNode.getParent().getRef().genericize(); TreeElement parentNode = instance.resolveReference(parentPath.contextualize(index.getReference())); return parentNode.getChildMultiplicity(templNode.getName()); }
private FormEntryPrompt findQuestion( FormEntryController formEntryContorller, TreeReference treeReferenceToMatch) { formEntryContorller.jumpToIndex(FormIndex.createBeginningOfFormIndex()); int event; while ((event = formEntryContorller.stepToNextEvent()) != FormEntryController.EVENT_END_OF_FORM) { if (event == FormEntryController.EVENT_QUESTION) { FormEntryPrompt questionPrompt = formEntryContorller.getModel().getQuestionPrompt(); QuestionDef thisQuestionDef = questionPrompt.getQuestion(); TreeReference thisTreeReference = (TreeReference) thisQuestionDef.getBind().getReference(); if (thisTreeReference.equals(treeReferenceToMatch)) return questionPrompt; } } return null; }
protected String substituteStringArgs(String templateStr) { if (templateStr == null) { return null; } return form.fillTemplateString(templateStr, index.getReference()); }
public static FormIndex createEndOfFormIndex() { FormIndex end = new FormIndex(-1, null); end.endOfForm = true; return end; }
public static FormIndex createBeginningOfFormIndex() { FormIndex begin = new FormIndex(-1, null); begin.beginningOfForm = true; return begin; }
public static boolean isSubElement(FormIndex parent, FormIndex child) { while (!parent.isTerminal() && !child.isTerminal()) { if (parent.getLocalIndex() != child.getLocalIndex()) { return false; } if (parent.getInstanceIndex() != child.getInstanceIndex()) { return false; } parent = parent.nextLevel; child = child.nextLevel; } // If we've gotten this far, at least one of the two is terminal if (!parent.isTerminal() && child.isTerminal()) { // can't be the parent if the child is earlier on return false; } else if (parent.getLocalIndex() != child.getLocalIndex()) { // Either they're at the same level, in which case only // identical indices should match, or they should have // the same root return false; } else if (parent.getInstanceIndex() != -1 && (parent.getInstanceIndex() != child.getInstanceIndex())) { return false; } // Barring all of these cases, it should be true. return true; }
public int getMultiplicity() { return index.getElementMultiplicity(); }
public void refreshView() { try { FormController formController = Collect.getInstance().getFormController(); // Record the current index so we can return to the same place if the user hits 'back'. currentIndex = formController.getFormIndex(); // If we're not at the first level, we're inside a repeated group so we want to only display // everything enclosed within that group. String contextGroupRef = ""; formList = new ArrayList<HierarchyElement>(); // If we're currently at a repeat node, record the name of the node and step to the next // node to display. if (formController.getEvent() == FormEntryController.EVENT_REPEAT) { contextGroupRef = formController.getFormIndex().getReference().toString(true); formController.stepToNextEvent(FormController.STEP_INTO_GROUP); } else { FormIndex startTest = formController.stepIndexOut(currentIndex); // If we have a 'group' tag, we want to step back until we hit a repeat or the // beginning. while (startTest != null && formController.getEvent(startTest) == FormEntryController.EVENT_GROUP) { startTest = formController.stepIndexOut(startTest); } if (startTest == null) { // check to see if the question is at the first level of the hierarchy. If it is, // display the root level from the beginning. formController.jumpToIndex(FormIndex.createBeginningOfFormIndex()); } else { // otherwise we're at a repeated group formController.jumpToIndex(startTest); } // now test again for repeat. This should be true at this point or we're at the // beginning if (formController.getEvent() == FormEntryController.EVENT_REPEAT) { contextGroupRef = formController.getFormIndex().getReference().toString(true); formController.stepToNextEvent(FormController.STEP_INTO_GROUP); } } int event = formController.getEvent(); if (event == FormEntryController.EVENT_BEGINNING_OF_FORM) { // The beginning of form has no valid prompt to display. formController.stepToNextEvent(FormController.STEP_INTO_GROUP); contextGroupRef = formController.getFormIndex().getReference().getParentRef().toString(true); mPath.setVisibility(View.GONE); jumpPreviousButton.setEnabled(false); } else { mPath.setVisibility(View.VISIBLE); mPath.setText(getCurrentPath()); jumpPreviousButton.setEnabled(true); } // Refresh the current event in case we did step forward. event = formController.getEvent(); // Big change from prior implementation: // // The ref strings now include the instance number designations // i.e., [0], [1], etc. of the repeat groups (and also [1] for // non-repeat elements). // // The contextGroupRef is now also valid for the top-level form. // // The repeatGroupRef is null if we are not skipping a repeat // section. // String repeatGroupRef = null; event_search: while (event != FormEntryController.EVENT_END_OF_FORM) { // get the ref to this element String currentRef = formController.getFormIndex().getReference().toString(true); // retrieve the current group String curGroup = (repeatGroupRef == null) ? contextGroupRef : repeatGroupRef; if (!currentRef.startsWith(curGroup)) { // We have left the current group if (repeatGroupRef == null) { // We are done. break event_search; } else { // exit the inner repeat group repeatGroupRef = null; } } if (repeatGroupRef != null) { // We're in a repeat group within the one we want to list // skip this question/group/repeat and move to the next index. event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP); continue; } switch (event) { case FormEntryController.EVENT_QUESTION: FormEntryPrompt fp = formController.getQuestionPrompt(); String label = fp.getLongText(); if (!fp.isReadOnly() || (label != null && label.length() > 0)) { // show the question if it is an editable field. // or if it is read-only and the label is not blank. formList.add( new HierarchyElement( fp.getLongText(), fp.getAnswerText(), null, Color.WHITE, QUESTION, fp.getIndex())); } break; case FormEntryController.EVENT_GROUP: // ignore group events break; case FormEntryController.EVENT_PROMPT_NEW_REPEAT: // this would display the 'add new repeat' dialog // ignore it. break; case FormEntryController.EVENT_REPEAT: FormEntryCaption fc = formController.getCaptionPrompt(); // push this repeat onto the stack. repeatGroupRef = currentRef; // Because of the guard conditions above, we will skip // everything until we exit this repeat. // // Note that currentRef includes the multiplicity of the // repeat (e.g., [0], [1], ...), so every repeat will be // detected as different and reach this case statement. // Only the [0] emits the repeat header. // Every one displays the descend-into action element. if (fc.getMultiplicity() == 0) { // Display the repeat header for the group. HierarchyElement group = new HierarchyElement( fc.getLongText(), null, getResources().getDrawable(R.drawable.expander_ic_minimized), Color.WHITE, COLLAPSED, fc.getIndex()); formList.add(group); } // Add this group name to the drop down list for this repeating group. HierarchyElement h = formList.get(formList.size() - 1); h.addChild( new HierarchyElement( mIndent + fc.getLongText() + " " + (fc.getMultiplicity() + 1), null, null, Color.WHITE, CHILD, fc.getIndex())); break; } event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP); } HierarchyListAdapter itla = new HierarchyListAdapter(this); itla.setListItems(formList); setListAdapter(itla); // set the controller back to the current index in case the user hits 'back' formController.jumpToIndex(currentIndex); } catch (Exception e) { Log.e(t, e.getMessage(), e); createErrorDialog(e.getMessage()); } }
public int compareTo(Object o) { if (!(o instanceof FormIndex)) throw new IllegalArgumentException( "Attempt to compare Object of type " + o.getClass().getName() + " to a FormIndex"); FormIndex a = this; FormIndex b = (FormIndex) o; if (a.beginningOfForm) { return (b.beginningOfForm ? 0 : -1); } else if (a.endOfForm) { return (b.endOfForm ? 0 : 1); } else { // a is in form if (b.beginningOfForm) { return 1; } else if (b.endOfForm) { return -1; } } if (a.localIndex != b.localIndex) { return (a.localIndex < b.localIndex ? -1 : 1); } else if (a.instanceIndex != b.instanceIndex) { return (a.instanceIndex < b.instanceIndex ? -1 : 1); } else if ((a.getNextLevel() == null) != (b.getNextLevel() == null)) { return (a.getNextLevel() == null ? -1 : 1); } else if (a.getNextLevel() != null) { return a.getNextLevel().compareTo(b.getNextLevel()); } else { return 0; } // int comp = 0; // // //TODO: while(true) loops freak me out, this should probably // //get written more safely. -ctsims // while(comp == 0) { // if(index.isTerminal() != local.isTerminal() || // index.getLocalIndex() != local.getLocalIndex() || // index.getInstanceIndex() != local.getInstanceIndex()) { // if(local.localIndex > index.localIndex) { // return 1; // } else if(local.localIndex < index.localIndex) { // return -1; // } else if (local.instanceIndex > index.instanceIndex) { // return 1; // } else if (local.instanceIndex < index.instanceIndex) { // return -1; // } // // //This case is here as a fallback, but it shouldn't really // //ever be the case that two references have the same chain // //of indices without terminating at the same level. // else if (local.isTerminal() && !index.isTerminal()) { // return -1; // } else { // return 1; // } // } // else if(local.isTerminal()) { // break; // } // local = local.getNextLevel(); // index = index.getNextLevel(); // } // return comp; }