Пример #1
0
    /**
     * Read serialized {@link FormDef} from file and recreate as object.
     *
     * @param formDef
     *          serialized FormDef file
     * @return {@link FormDef} object
     */
    public FormDef deserializeFormDef(File formDef) {

        // TODO: any way to remove reliance on jrsp?
        FileInputStream fis = null;
        FormDef fd = null;
        try {
            // create new form def
            fd = new FormDef();
            fis = new FileInputStream(formDef);
            DataInputStream dis = new DataInputStream(fis);

            // read serialized formdef into new formdef
            fd.readExternal(dis, ExtUtil.defaultPrototypes());
            dis.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            fd = null;
        } catch (IOException e) {
            e.printStackTrace();
            fd = null;
        } catch (DeserializationException e) {
            e.printStackTrace();
            fd = null;
        } catch (Exception e) {
            e.printStackTrace();
            fd = null;
        }

        return fd;
    }
 protected FieldSpecCollection createFieldSpecsFromXForms(FormEntryController formEntryController)
     throws Exception {
   FormDef formDef = formEntryController.getModel().getForm();
   List<IFormElement> children = formDef.getChildren();
   unGroupedUniqueId = 0;
   return recursivelyConvertXFormsFieldsToFieldSpecs(formEntryController, children, false);
 }
Пример #3
0
	protected JrFormEntryController getController() {

		Vector<IPreloadHandler> preloaders = JRDemoContext._().getPreloaders();
		Vector<IFunctionHandler> funcHandlers = JRDemoContext._().getFuncHandlers();
		FormDefFetcher fetcher = new FormDefFetcher(new RMSRetreivalMethod(formID), preloaders, funcHandlers);
		FormDef form = fetcher.getFormDef();
		
		JrFormEntryController controller =  new JrFormEntryController(new JrFormEntryModel(form));
		String title = form.getTitle();
		if(title == null) {
			title = "Enter Data";
		}
		controller.setView(new JRDemoFormEntryViewFactory(title).getFormEntryView(controller));
		return controller;
	}
  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;
    }
  }
 /**
  * Creates a FormEntryCaption for the element at the given index in the form.
  *
  * @param form
  * @param index
  */
 public FormEntryCaption(FormDef form, FormIndex index) {
   this.form = form;
   this.index = index;
   this.element = form.getChild(index);
   this.viewWidget = null;
   this.textID = this.element.getTextID();
 }
  // 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 RepeatOptions getRepeatOptions() {
    RepeatOptions ro = new RepeatOptions();
    boolean has_repetitions = (getNumRepetitions() > 0);

    ro.header = getRepeatText("mainheader");

    ro.add = null;
    if (form.canCreateRepeat(form.getChildInstanceRef(index), index)) {
      ro.add = getRepeatText(has_repetitions ? "add" : "add-empty");
    }
    ro.delete = null;
    ro.delete_header = null;
    if (has_repetitions) {
      ro.delete = getRepeatText("del");
      ro.delete_header = getRepeatText("delheader");
    }
    ro.done = getRepeatText(has_repetitions ? "done" : "done-empty");

    return ro;
  }
  public List<String> getRepetitionsText() {
    GroupDef g = (GroupDef) element;
    if (!g.getRepeat()) {
      throw new RuntimeException("not a repeat");
    }

    int numRepetitions = getNumRepetitions();
    List<String> reps = new ArrayList<String>(numRepetitions);
    for (int i = 0; i < numRepetitions; i++) {
      reps.add(getRepetitionText("choose", form.descendIntoRepeat(index, i), false));
    }
    return reps;
  }
Пример #9
0
	public void formEntrySaved(FormDef form, FormInstance instanceData, boolean formWasCompleted) {
		System.out.println("form is complete: " + formWasCompleted);
 
		//Warning, this might be null
		final SubmissionProfile profile = form.getSubmissionProfile();
		
		if (formWasCompleted) {
			
			// We want to cache this send before we actually ask, otherwise the user could quit before it is
			// either sent _or_ saved.
			
			IStorageUtility storage = StorageManager.getStorage(FormInstance.STORAGE_KEY);
			try {
				Logger.log("formentry","writing data: " + instanceData.getName());
				storage.write(instanceData);
				final int record = instanceData.getID();

				TransportMessage message = JRDemoContext._().buildMessage(instanceData, profile);
				
				CompletedFormOptionsState completed = new CompletedFormOptionsState(message) {
	
					public void sendData(TransportMessage message) {
						
						JRDemoFormTransportState send = new JRDemoFormTransportState(message, record) {
							public void done() {
								JRDemoUtil.goToList(cameFromFormList);
							}
		
							public void sendToBackground() {
								JRDemoUtil.goToList(cameFromFormList);
							}
						};
							
						send.start();
					}
	
					public void skipSend(TransportMessage message) {
						// Message should already be cached.
						abort();
					}
				};
				completed.start();
			} catch (StorageFullException e) {
				new RuntimeException("Storage full, unable to save data.");
			}
		} else {
			abort();
		}
	}
Пример #10
0
    /**
     * Write the FormDef to the file system as a binary blog.
     *
     * @param filepath
     *          path to the form file
     */
    public void serializeFormDef(FormDef fd, String filepath) {
        // calculate unique md5 identifier
        String hash = FileUtils.getMd5Hash(new File(filepath));
        File formDef = new File(Collect.CACHE_PATH + File.separator + hash + ".formdef");

        // formdef does not exist, create one.
        if (!formDef.exists()) {
            FileOutputStream fos;
            try {
                fos = new FileOutputStream(formDef);
                DataOutputStream dos = new DataOutputStream(fos);
                fd.writeExternal(dos);
                dos.flush();
                dos.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
Пример #11
0
  protected ItemsetWidget(
      Context context, FormEntryPrompt prompt, boolean readOnlyOverride, boolean derived) {
    super(context, prompt);
    mButtons = new RadioGroup(context);
    mButtons.setId(QuestionWidget.newUniqueId());
    mReadOnly = prompt.isReadOnly() || readOnlyOverride;
    mAnswers = new HashMap<String, String>();

    String currentAnswer = prompt.getAnswerText();

    // the format of the query should be something like this:
    // query="instance('cities')/root/item[state=/data/state and county=/data/county]"

    // "query" is what we're using to notify that this is an
    // itemset widget.
    String nodesetStr = prompt.getQuestion().getAdditionalAttribute(null, "query");

    // parse out the list name, between the ''
    String list_name =
        nodesetStr.substring(nodesetStr.indexOf("'") + 1, nodesetStr.lastIndexOf("'"));

    // isolate the string between between the [ ] characters
    String queryString =
        nodesetStr.substring(nodesetStr.indexOf("[") + 1, nodesetStr.lastIndexOf("]"));

    StringBuilder selection = new StringBuilder();
    // add the list name as the first argument, which will always be there
    selection.append("list_name=?");

    // check to see if there are any arguments
    if (queryString.indexOf("=") != -1) {
      selection.append(" and ");
    }

    // can't just split on 'and' or 'or' because they have different
    // behavior, so loop through and break them off until we don't have any
    // more
    // must include the spaces in indexOf so we don't match words like
    // "land"
    int andIndex = -1;
    int orIndex = -1;
    ArrayList<String> arguments = new ArrayList<String>();
    while ((andIndex = queryString.indexOf(" and ")) != -1
        || (orIndex = queryString.indexOf(" or ")) != -1) {
      if (andIndex != -1) {
        String subString = queryString.substring(0, andIndex);
        String pair[] = subString.split("=");
        if (pair.length == 2) {
          selection.append(pair[0].trim() + "=? and ");
          arguments.add(pair[1].trim());
        } else {
          // parse error
        }
        // move string forward to after " and "
        queryString = queryString.substring(andIndex + 5, queryString.length());
        andIndex = -1;
      } else if (orIndex != -1) {
        String subString = queryString.substring(0, orIndex);
        String pair[] = subString.split("=");
        if (pair.length == 2) {
          selection.append(pair[0].trim() + "=? or ");
          arguments.add(pair[1].trim());
        } else {
          // parse error
        }

        // move string forward to after " or "
        queryString = queryString.substring(orIndex + 4, queryString.length());
        orIndex = -1;
      }
    }

    // parse the last segment (or only segment if there are no 'and' or 'or'
    // clauses
    String pair[] = queryString.split("=");
    if (pair.length == 2) {
      selection.append(pair[0].trim() + "=?");
      arguments.add(pair[1].trim());
    }
    if (pair.length == 1) {
      // this is probably okay, because then you just list all items in
      // the list
    } else {
      // parse error
    }

    // +1 is for the list_name
    String[] selectionArgs = new String[arguments.size() + 1];

    boolean nullArgs = false; // can't have any null arguments
    selectionArgs[0] = list_name; // first argument is always listname

    // loop through the arguments, evaluate any expressions
    // and build the query string for the DB
    for (int i = 0; i < arguments.size(); i++) {
      XPathExpression xpr = null;
      try {
        xpr = XPathParseTool.parseXPath(arguments.get(i));
      } catch (XPathSyntaxException e) {
        e.printStackTrace();
        TextView error = new TextView(context);
        error.setText("XPathParser Exception:  \"" + arguments.get(i) + "\"");
        addView(error);
        break;
      }

      if (xpr != null) {
        FormDef form = Collect.getInstance().getFormController().getFormDef();
        TreeElement mTreeElement =
            form.getMainInstance().resolveReference(prompt.getIndex().getReference());
        EvaluationContext ec =
            new EvaluationContext(form.getEvaluationContext(), mTreeElement.getRef());
        Object value = xpr.eval(form.getMainInstance(), ec);

        if (value == null) {
          nullArgs = true;
        } else {
          if (value instanceof XPathNodeset) {
            XPathNodeset xpn = (XPathNodeset) value;
            value = xpn.getValAt(0);
          }

          selectionArgs[i + 1] = value.toString();
        }
      }
    }

    File itemsetFile =
        new File(
            Collect.getInstance().getFormController().getMediaFolder().getAbsolutePath()
                + "/itemsets.csv");
    if (nullArgs) {
      // we can't try to query with null values else it blows up
      // so just leave the screen blank
      // TODO: put an error?
    } else if (itemsetFile.exists()) {
      ItemsetDbAdapter ida = new ItemsetDbAdapter();
      ida.open();

      // name of the itemset table for this form
      String pathHash = ItemsetDbAdapter.getMd5FromString(itemsetFile.getAbsolutePath());
      try {
        Cursor c = ida.query(pathHash, selection.toString(), selectionArgs);
        if (c != null) {
          c.move(-1);
          while (c.moveToNext()) {
            String label = "";
            String val = "";
            // try to get the value associated with the label:lang
            // string if that doen't exist, then just use label
            String lang = "";
            if (Collect.getInstance().getFormController().getLanguages() != null
                && Collect.getInstance().getFormController().getLanguages().length > 0) {
              lang = Collect.getInstance().getFormController().getLanguage();
            }

            // apparently you only need the double quotes in the
            // column name when creating the column with a :
            // included
            String labelLang = "label" + "::" + lang;
            int langCol = c.getColumnIndex(labelLang);
            if (langCol == -1) {
              label = c.getString(c.getColumnIndex("label"));
            } else {
              label = c.getString(c.getColumnIndex(labelLang));
            }

            // the actual value is stored in name
            val = c.getString(c.getColumnIndex("name"));
            mAnswers.put(label, val);

            RadioButton rb = new RadioButton(context);
            rb.setOnCheckedChangeListener(this);
            rb.setText(label);
            rb.setTextSize(mAnswerFontsize);
            mButtons.addView(rb);
            // have to add it to the radiogroup before checking it,
            // else it lets two buttons be checked...
            if (currentAnswer != null && val.compareTo(currentAnswer) == 0) {
              rb.setChecked(true);
            }
          }
          c.close();
        }
      } finally {
        ida.close();
      }

      addView(mButtons);
    } else {
      TextView error = new TextView(context);
      error.setText(getContext().getString(R.string.file_missing, itemsetFile.getAbsolutePath()));
      addView(error);
    }
  }
Пример #12
0
    /**
     * Initialize {@link FormEntryController} with {@link FormDef} from binary or
     * from XML. If given an instance, it will be used to fill the {@link FormDef}
     * .
     */
    @Override
    protected FECWrapper doInBackground(String... path) {
        FormEntryController fec = null;
        FormDef fd = null;
        FileInputStream fis = null;
        mErrorMsg = null;

        String formPath = path[0];

        File formXml = new File(formPath);
        String formHash = FileUtils.getMd5Hash(formXml);
        File formBin = new File(Collect.CACHE_PATH + File.separator + formHash + ".formdef");

        publishProgress(Collect.getInstance().getString(R.string.survey_loading_reading_form_message));

        FormDef.EvalBehavior mode = AdminPreferencesActivity.getConfiguredFormProcessingLogic(Collect.getInstance());
        FormDef.setEvalBehavior(mode);

//    FormDef.setDefaultEventNotifier(new EventNotifier() {
//
//      @Override
//      public void publishEvent(Event event) {
//        Log.d("FormDef", event.asLogLine());
//      }
//    });

        if (formBin.exists()) {
            // if we have binary, deserialize binary
            Log.i(
                    t,
                    "Attempting to load " + formXml.getName() + " from cached file: "
                            + formBin.getAbsolutePath());
            fd = deserializeFormDef(formBin);
            if (fd == null) {
                // some error occured with deserialization. Remove the file, and make a
                // new .formdef
                // from xml
                Log.w(t, "Deserialization FAILED!  Deleting cache file: " + formBin.getAbsolutePath());
                formBin.delete();
            }
        }
        if (fd == null) {
            // no binary, read from xml
            try {
                Log.i(t, "Attempting to load from: " + formXml.getAbsolutePath());
                fis = new FileInputStream(formXml);
                fd = XFormUtils.getFormFromInputStream(fis);
                if (fd == null) {
                    mErrorMsg = "Error reading XForm file";
                } else {
                    serializeFormDef(fd, formPath);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                mErrorMsg = e.getMessage();
            } catch (XFormParseException e) {
                mErrorMsg = e.getMessage();
                e.printStackTrace();
            } catch (Exception e) {
                mErrorMsg = e.getMessage();
                e.printStackTrace();
            } finally {
                IOUtils.closeQuietly(fis);
            }
        }

        if (mErrorMsg != null || fd == null) {
            return null;
        }

        // set paths to /sdcard/odk/forms/formfilename-media/
        String formFileName = formXml.getName().substring(0, formXml.getName().lastIndexOf("."));
        File formMediaDir = new File(formXml.getParent(), formFileName + "-media");

        externalDataManager = new ExternalDataManagerImpl(formMediaDir);

        // add external data function handlers
        ExternalDataHandler externalDataHandlerPull = new ExternalDataHandlerPull(externalDataManager);
        fd.getEvaluationContext().addFunctionHandler(externalDataHandlerPull);

        try {
            loadExternalData(formMediaDir);
        } catch (Exception e) {
            mErrorMsg = e.getMessage();
            e.printStackTrace();
            return null;
        }

        if (isCancelled()) {
            // that means that the user has cancelled, so no need to go further
            return null;
        }

        // create FormEntryController from formdef
        FormEntryModel fem = new FormEntryModel(fd);
        fec = new FormEntryController(fem);

        boolean usedSavepoint = false;

        try {
            // import existing data into formdef
            if (mInstancePath != null) {
                File instance = new File(mInstancePath);
                File shadowInstance = SaveToDiskTask.savepointFile(instance);
                if (shadowInstance.exists() && (shadowInstance.lastModified() > instance.lastModified())) {
                    // the savepoint is newer than the saved value of the instance.
                    // use it.
                    usedSavepoint = true;
                    instance = shadowInstance;
                    Log.w(t, "Loading instance from shadow file: " + shadowInstance.getAbsolutePath());
                }
                if (instance.exists()) {
                    // This order is important. Import data, then initialize.
                    try {
                        importData(instance, fec);
                        fd.initialize(false, new InstanceInitializationFactory());
                    } catch (RuntimeException e) {
                        Log.e(t, e.getMessage(), e);

                        // SCTO-633
                        if (usedSavepoint && !(e.getCause() instanceof XPathTypeMismatchException)) {
                            // this means that the .save file is corrupted or 0-sized, so
                            // don't use it.
                            usedSavepoint = false;
                            mInstancePath = null;
                            fd.initialize(true, new InstanceInitializationFactory());
                        } else {
                            // this means that the saved instance is corrupted.
                            throw e;
                        }
                    }
                } else {
                    fd.initialize(true, new InstanceInitializationFactory());
                }
            } else {
                fd.initialize(true, new InstanceInitializationFactory());
            }
        } catch (RuntimeException e) {
            Log.e(t, e.getMessage(), e);
            if (e.getCause() instanceof XPathTypeMismatchException) {
                // this is a case of
                // https://bitbucket.org/m.sundt/javarosa/commits/e5d344783e7968877402bcee11828fa55fac69de
                // the data are imported, the survey will be unusable
                // but we should give the option to the user to edit the form
                // otherwise the survey will be TOTALLY inaccessible.
                Log.w(
                        t,
                        "We have a syntactically correct instance, but the data threw an exception inside JR. We should allow editing.");
            } else {
                mErrorMsg = e.getMessage();
                return null;
            }
        }

        // Remove previous forms
        ReferenceManager._().clearSession();

        // for itemsets.csv, we only check to see if the itemset file has been
        // updated
        File csv = new File(formMediaDir.getAbsolutePath() + "/" + ITEMSETS_CSV);
        String csvmd5 = null;
        if (csv.exists()) {
            csvmd5 = FileUtils.getMd5Hash(csv);
            boolean readFile = false;
            ItemsetDbAdapter ida = new ItemsetDbAdapter();
            ida.open();
            // get the database entry (if exists) for this itemsets.csv, based
            // on the path
            Cursor c = ida.getItemsets(csv.getAbsolutePath());
            if (c != null) {
                if (c.getCount() == 1) {
                    c.moveToFirst(); // should be only one, ever, if any
                    String oldmd5 = c.getString(c.getColumnIndex("hash"));
                    if (oldmd5.equals(csvmd5)) {
                        // they're equal, do nothing
                    } else {
                        // the csv has been updated, delete the old entries
                        ida.dropTable(ItemsetDbAdapter.getMd5FromString(csv.getAbsolutePath()),
                                csv.getAbsolutePath());
                        // and read the new
                        readFile = true;
                    }
                } else {
                    // new csv, add it
                    readFile = true;
                }
                c.close();
            }
            ida.close();
            if (readFile) {
                readCSV(csv, csvmd5, ItemsetDbAdapter.getMd5FromString(csv.getAbsolutePath()));
            }
        }

        // This should get moved to the Application Class
        if (ReferenceManager._().getFactories().length == 0) {
            // this is /sdcard/odk
            ReferenceManager._().addReferenceFactory(new FileReferenceFactory(Collect.ODK_ROOT));
        }

        // Set jr://... to point to /sdcard/odk/forms/filename-media/
        ReferenceManager._().addSessionRootTranslator(
                new RootTranslator("jr://images/", "jr://file/forms/" + formFileName + "-media/"));
        ReferenceManager._().addSessionRootTranslator(
                new RootTranslator("jr://image/", "jr://file/forms/" + formFileName + "-media/"));
        ReferenceManager._().addSessionRootTranslator(
                new RootTranslator("jr://audio/", "jr://file/forms/" + formFileName + "-media/"));
        ReferenceManager._().addSessionRootTranslator(
                new RootTranslator("jr://video/", "jr://file/forms/" + formFileName + "-media/"));

        // clean up vars
        fis = null;
        fd = null;
        formBin = null;
        formXml = null;
        formPath = null;

        FormController fc = new FormController(formMediaDir, fec, mInstancePath == null ? null
                : new File(mInstancePath));
        if (mXPath != null) {
            // we are resuming after having terminated -- set index to this
            // position...
            FormIndex idx = fc.getIndexFromXPath(mXPath);
            fc.jumpToIndex(idx);
        }
        if (mWaitingXPath != null) {
            FormIndex idx = fc.getIndexFromXPath(mWaitingXPath);
            fc.setIndexWaitingForData(idx);
        }
        data = new FECWrapper(fc, usedSavepoint);
        return data;

    }
Пример #13
0
 protected String substituteStringArgs(String templateStr) {
   if (templateStr == null) {
     return null;
   }
   return form.fillTemplateString(templateStr, index.getReference());
 }
Пример #14
0
 // this should probably be somewhere better
 public int getNumRepetitions() {
   return form.getNumRepetitions(index);
 }