/*
* Geopaparazzi - Digital field mapping on Android based devices
* Copyright (C) 2010 HydroloGIS (www.hydrologis.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.geopaparazzi.library.forms;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.TimePickerDialog;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import eu.geopaparazzi.library.forms.constraints.Constraints;
import eu.geopaparazzi.library.forms.constraints.MandatoryConstraint;
import eu.geopaparazzi.library.forms.constraints.RangeConstraint;
import eu.geopaparazzi.library.forms.views.GBooleanView;
import eu.geopaparazzi.library.forms.views.GComboView;
import eu.geopaparazzi.library.forms.views.GDateView;
import eu.geopaparazzi.library.forms.views.GEditTextView;
import eu.geopaparazzi.library.forms.views.GMapView;
import eu.geopaparazzi.library.forms.views.GMultiComboView;
import eu.geopaparazzi.library.forms.views.GNfcUidView;
import eu.geopaparazzi.library.forms.views.GPictureView;
import eu.geopaparazzi.library.forms.views.GSketchView;
import eu.geopaparazzi.library.forms.views.GTextView;
import eu.geopaparazzi.library.forms.views.GTimeView;
import eu.geopaparazzi.library.forms.views.GView;
import eu.geopaparazzi.library.util.MultipleChoiceDialog;
import eu.geopaparazzi.library.util.Utilities;
/**
* Utilities methods for form stuff.
*
* @author Andrea Antonello (www.hydrologis.com)
* @since 2.6
*/
@SuppressWarnings("nls")
public class FormUtilities {
public static final String COLON = ":";
public static final String UNDERSCORE = "_";
/**
* Type for a {@link TextView}.
*/
public static final String TYPE_LABEL = "label";
/**
* Type for a {@link TextView} with line below.
*/
public static final String TYPE_LABELWITHLINE = "labelwithline";
/**
* Type for a {@link EditText} containing generic text.
*/
public static final String TYPE_STRING = "string";
/**
* Type for a {@link EditText} area containing generic text.
*/
public static final String TYPE_STRINGAREA = "stringarea";
/**
* Type for a {@link EditText} containing generic numbers.
*/
public static final String TYPE_DOUBLE = "double";
/**
* Type for a {@link Button} containing date.
*/
public static final String TYPE_DATE = "date";
/**
* Type for a {@link Button} containing time.
*/
public static final String TYPE_TIME = "time";
/**
* Type for a {@link CheckBox}.
*/
public static final String TYPE_BOOLEAN = "boolean";
/**
* Type for a {@link Spinner}.
*/
public static final String TYPE_STRINGCOMBO = "stringcombo";
/**
* Type for a {@link MuSpinner}.
*/
public static final String TYPE_STRINGMULTIPLECHOICE = "multistringcombo";
/**
* Type for a the NFC UID reader.
*/
public static final String TYPE_NFCUID = "nfcuid";
/**
* Type for a hidden widget, which just needs to be kept as it is but not displayed.
*/
public static final String TYPE_HIDDEN = "hidden";
/**
* Type for latitude, which can be substituted by the engine if necessary.
*/
public static final String TYPE_LATITUDE = "LATITUDE";
/**
* Type for longitude, which can be substituted by the engine if necessary.
*/
public static final String TYPE_LONGITUDE = "LONGITUDE";
/**
* Type for a hidden item, the value of which needs to get the name of the element.
*
* <p>This is needed in case of abstraction of forms.</p>
*/
public static final String TYPE_PRIMARYKEY = "primary_key";
/**
* Type for pictures element.
*/
public static final String TYPE_PICTURES = "pictures";
/**
* Type for pictures element.
*/
public static final String TYPE_SKETCH = "sketch";
/**
* Type for map element.
*/
public static final String TYPE_MAP = "map";
/**
* Type for barcode element.
*
* <b>Not in use yet.</b>
*/
public static final String TYPE_BARCODE = "barcode";
/**
* A constraint that defines the item as mandatory.
*/
public static final String CONSTRAINT_MANDATORY = "mandatory";
/**
* A constraint that defines a range for the value.
*/
public static final String CONSTRAINT_RANGE = "range";
public static final String ATTR_SECTIONNAME = "sectionname";
public static final String ATTR_SECTIONOBJECTSTR = "sectionobjectstr";
public static final String ATTR_FORMS = "forms";
public static final String ATTR_FORMNAME = "formname";
public static final String TAG_LONGNAME = "longname";
public static final String TAG_SHORTNAME = "shortname";
public static final String TAG_FORMS = "forms";
public static final String TAG_FORMITEMS = "formitems";
public static final String TAG_KEY = "key";
public static final String TAG_VALUE = "value";
public static final String TAG_ISLABEL = "islabel";
public static final String TAG_VALUES = "values";
public static final String TAG_ITEMS = "items";
public static final String TAG_ITEM = "item";
public static final String TAG_TYPE = "type";
public static final String TAG_READONLY = "readonly";
public static final String TAG_SIZE = "size";
public static final String TAG_URL = "url";
/**
* Checks if the type is a special one.
*
* @param typethe type string from the form.
* @return <code>true</code> if the type is special.
*/
public static boolean isTypeSpecial( String type ) {
if (type.equals(TYPE_PRIMARYKEY)) {
return true;
} else if (type.equals(TYPE_HIDDEN)) {
return true;
}
return false;
}
/**
* Adds a {@link TextView} to the supplied mainView.
*
* @param context the context.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param type the text type:
* <ul>
* <li>0: text</li>
* <li>1: numeric</li>
* <li>2: phone</li>
* <li>3: date</li>
* </ul>
* @param lines lines or 0
* @param constraintDescription
* @param readonly
* @return the added view.
*/
public static GView addEditText( Context context, LinearLayout mainView, String key, String value, int type, int lines,
String constraintDescription, boolean readonly ) {
GEditTextView editText = new GEditTextView(context, null, mainView, key, value, type, lines, constraintDescription,
readonly);
return editText;
}
public static GView addTextView( final Context context, LinearLayout mainView, String value, String size, boolean withLine,
final String url ) {
GTextView textView = new GTextView(context, null, mainView, value, size, withLine, url);
return textView;
}
/**
* Adds a {@link CheckBox} to the supplied mainView.
*
* @param context the context.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param constraintDescription
* @param readonly
* @return the added view.
*/
public static GView addBooleanView( Context context, LinearLayout mainView, String key, String value,
String constraintDescription, boolean readonly ) {
GBooleanView booleanView = new GBooleanView(context, null, mainView, key, value, constraintDescription, readonly);
return booleanView;
}
/**
* Adds a {@link Spinner} to the supplied mainView.
*
* @param context the context.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param itemsArray the items to put in the spinner.
* @param constraintDescription
* @return the added view.
*/
public static GView addComboView( Context context, LinearLayout mainView, String key, String value, String[] itemsArray,
String constraintDescription ) {
GComboView comboView = new GComboView(context, null, mainView, key, value, itemsArray, constraintDescription);
return comboView;
}
/**
* Adds a {@link MultipleChoiceDialog} to the supplied mainView.
*
* @param context the context.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param itemsArray the items to put in the spinner.
* @param constraintDescription
* @return the added view.
*/
public static GView addMultiSelectionView( final Context context, LinearLayout mainView, String key, String value,
final String[] itemsArray, String constraintDescription ) {
GMultiComboView comboView = new GMultiComboView(context, null, mainView, key, value, itemsArray, constraintDescription);
return comboView;
}
public static GView addPictureView( final Context context, LinearLayout mainView, String key, String value,
String constraintDescription ) {
GPictureView pictureView = new GPictureView(context, null, mainView, key, value, constraintDescription);
return pictureView;
}
public static GView addSketchView( final Context context, LinearLayout mainView, String key, String value,
String constraintDescription ) {
GSketchView sketch = new GSketchView(context, null, mainView, key, value, constraintDescription);
return sketch;
}
/**
* @param context
* @param mainView
* @param key
* @param value needs to be a relative path to the media image (ex. media/IMG_20120202.png)
* @param constraintDescription
* @return
*/
public static GView addMapView( final Context context, LinearLayout mainView, String key, String value,
String constraintDescription ) {
GMapView mapView = new GMapView(context, null, mainView, key, value, constraintDescription);
return mapView;
}
/**
* Adds a {@link DatePicker} to the supplied mainView.
*
* @param fragment the parent {@link Fragment}.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param itemsArray the items to put in the spinner.
* @param constraintDescription
* @param readonly
* @return the added view.
*/
public static GView addDateView( final Fragment fragment, LinearLayout mainView, String key, String value,
String constraintDescription, boolean readonly ) {
GDateView dateView = new GDateView(fragment, null, mainView, key, value, constraintDescription, readonly);
return dateView;
}
/**
* Adds a {@link TimePickerDialog} to the supplied mainView.
*
* @param fragment the parent {@link Fragment}.
* @param mainView the main view to which to add the new widget to.
* @param key the key identifying the widget.
* @param value the value to put in the widget.
* @param itemsArray the items to put in the spinner.
* @param constraintDescription
* @param readonly
* @return the added view.
*/
public static GView addTimeView( final Fragment fragment, LinearLayout mainView, String key, String value,
String constraintDescription, boolean readonly ) {
GTimeView timeView = new GTimeView(fragment, null, mainView, key, value, constraintDescription, readonly);
return timeView;
}
public static GView addNfcUIDView( Activity activity, int requestCode, LinearLayout mainView, String key, String value,
String constraintDescription ) {
GNfcUidView nfcuidView = new GNfcUidView(activity, null, requestCode, mainView, key, value, constraintDescription);
return nfcuidView;
}
/**
* Check an {@link JSONObject object} for constraints and collect them.
*
* @param jsonObject the object to check.
* @param constraints the {@link Constraints} object to use or <code>null</code>.
* @return the original {@link Constraints} object or a new created.
* @throws Exception
*/
public static Constraints handleConstraints( JSONObject jsonObject, Constraints constraints ) throws Exception {
if (constraints == null)
constraints = new Constraints();
if (jsonObject.has(CONSTRAINT_MANDATORY)) {
String mandatory = jsonObject.getString(CONSTRAINT_MANDATORY).trim();
if (mandatory.trim().equals("yes")) {
constraints.addConstraint(new MandatoryConstraint());
}
}
if (jsonObject.has(CONSTRAINT_RANGE)) {
String range = jsonObject.getString(CONSTRAINT_RANGE).trim();
String[] rangeSplit = range.split(",");
if (rangeSplit.length == 2) {
boolean lowIncluded = rangeSplit[0].startsWith("[") ? true : false;
String lowStr = rangeSplit[0].substring(1);
Double low = Utilities.adapt(lowStr, Double.class);
boolean highIncluded = rangeSplit[1].endsWith("]") ? true : false;
String highStr = rangeSplit[1].substring(0, rangeSplit[1].length() - 1);
Double high = Utilities.adapt(highStr, Double.class);
constraints.addConstraint(new RangeConstraint(low, lowIncluded, high, highIncluded));
}
}
return constraints;
}
/**
* Updates a form items array with the given kay/value pair.
*
* @param formItemsArray the array to update.
* @param key the key of the item to update.
* @param value the new value to use.
* @throws JSONException
*/
public static void update( JSONArray formItemsArray, String key, String value ) throws JSONException {
int length = formItemsArray.length();
for( int i = 0; i < length; i++ ) {
JSONObject itemObject = formItemsArray.getJSONObject(i);
if (itemObject.has(TAG_KEY)) {
String objKey = itemObject.getString(TAG_KEY).trim();
if (objKey.equals(key)) {
itemObject.put(TAG_VALUE, value);
}
}
}
}
/**
* Update those fields that do not generate widgets.
*
* @param formItemsArray the items array.
* @param latitude the lat value.
* @param longitude the long value.
* @throws JSONException
*/
public static void updateExtras( JSONArray formItemsArray, double latitude, double longitude ) throws JSONException {
int length = formItemsArray.length();
for( int i = 0; i < length; i++ ) {
JSONObject itemObject = formItemsArray.getJSONObject(i);
if (itemObject.has(TAG_KEY)) {
String objKey = itemObject.getString(TAG_KEY).trim();
if (objKey.equals(TYPE_LATITUDE)) {
itemObject.put(TAG_VALUE, latitude);
} else if (objKey.equals(TYPE_LONGITUDE)) {
itemObject.put(TAG_VALUE, longitude);
}
}
}
}
}