/**
* Odoo, Open Source Management Solution
* Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http:www.gnu.org/licenses/>
*
* Created on 7/1/15 5:10 PM
*/
package odoo.controls;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.odoo.core.orm.ODataRow;
import com.odoo.core.orm.OModel;
import com.odoo.core.orm.fields.OColumn;
import com.odoo.core.orm.fields.types.OBlob;
import com.odoo.core.orm.fields.types.OBoolean;
import com.odoo.core.orm.fields.types.ODate;
import com.odoo.core.orm.fields.types.ODateTime;
import com.odoo.core.orm.fields.types.OFloat;
import com.odoo.core.orm.fields.types.OHtml;
import com.odoo.core.orm.fields.types.OInteger;
import com.odoo.core.orm.fields.types.OSelection;
import com.odoo.core.orm.fields.types.OText;
import com.odoo.core.orm.fields.types.OTimestamp;
import com.odoo.core.orm.fields.types.OVarchar;
import com.odoo.R;
public class OField extends LinearLayout implements IOControlData.ValueUpdateListener {
public static final String TAG = OField.class.getSimpleName();
private Context mContext = null;
private FieldType mType = FieldType.Text;
private OColumn mColumn = null;
private OModel mModel = null;
private String mLabel, mField_name;
private Object mValue = null;
private boolean mEditable = false, showIcon = true, show_label = true;
private TextView label_view = null;
private int resId, tint_color = Color.BLACK, mValueArrayId = -1;
private ImageView img_icon = null;
private ViewGroup container = null;
private Boolean with_bottom_padding = true, with_top_padding = true;
private WidgetType mWidgetType = null;
private String mParsePattern = null;
private IOnChangeCallback mOnChangeCallback = null;
private IOnDomainFilterCallbacks mOnDomainFilterCallbacks = null;
private OColumn.ColumnDomain mColumnDomain = null;
private float mWidgetImageSize = -1;
private Boolean withPadding = true;
// Controls
private IOControlData mControlData = null;
private Boolean useTemplate = true;
private Integer defaultImage = -1;
// Appearance
private int textColor = Color.BLACK;
private int labelColor = Color.DKGRAY;
private int textAppearance = -1;
private int labelAppearance = -1;
private float textSize = -1;
private float labelSize = -1;
private IOnFieldValueChangeListener mValueUpdateListener = null;
public enum WidgetType {
Switch, RadioGroup, SelectionDialog, Searchable, SearchableLive, Image, ImageCircle, Duration;
public static WidgetType getWidgetType(int widget) {
switch (widget) {
case 0:
return WidgetType.Switch;
case 1:
return WidgetType.RadioGroup;
case 2:
return WidgetType.SelectionDialog;
case 3:
return WidgetType.Searchable;
case 4:
return WidgetType.SearchableLive;
case 5:
return WidgetType.Image;
case 6:
return WidgetType.ImageCircle;
case 7:
return WidgetType.Duration;
}
return null;
}
}
public enum FieldType {
Text, Boolean, ManyToOne, Chips, Selection, Date, Time, DateTime, Blob, RelationType;
public static FieldType getTypeValue(int type_val) {
switch (type_val) {
case 0:
return FieldType.Text;
case 1:
return FieldType.Boolean;
case 2:
return FieldType.ManyToOne;
case 3:
return FieldType.Chips;
case 4:
return FieldType.Selection;
case 5:
return FieldType.Date;
case 6:
return FieldType.DateTime;
case 7:
return FieldType.Blob;
case 8:
return FieldType.Time;
}
return FieldType.Text;
}
}
public OField(Context context) {
super(context);
init(context, null, 0, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public OField(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, defStyleRes);
}
public OField(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
public OField(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
mContext = context;
if (attrs != null) {
TypedArray types = mContext.obtainStyledAttributes(attrs,
R.styleable.OField);
mField_name = types.getString(R.styleable.OField_fieldName);
resId = types.getResourceId(R.styleable.OField_iconResource, 0);
showIcon = types.getBoolean(R.styleable.OField_showIcon, true);
tint_color = types.getColor(R.styleable.OField_iconTint, 0);
show_label = types.getBoolean(R.styleable.OField_showLabel, true);
int type_value = types.getInt(R.styleable.OField_fieldType, 0);
mType = FieldType.getTypeValue(type_value);
with_bottom_padding = types.getBoolean(
R.styleable.OField_withBottomPadding, true);
with_top_padding = types.getBoolean(
R.styleable.OField_withTopPadding, true);
mLabel = types.getString(R.styleable.OField_controlLabel);
mValue = types.getString(R.styleable.OField_defaultValue);
mParsePattern = types.getString(R.styleable.OField_parsePattern);
mValueArrayId = types.getResourceId(
R.styleable.OField_valueArray, -1);
mWidgetType = WidgetType.getWidgetType(types.getInt(
R.styleable.OField_widgetType, -1));
mWidgetImageSize = types.getDimension(R.styleable.OField_widgetImageSize, -1);
withPadding = types.getBoolean(R.styleable.OField_withOutSidePadding, true);
textColor = types.getColor(R.styleable.OField_fieldTextColor, Color.BLACK);
labelColor = types.getColor(R.styleable.OField_fieldLabelColor, Color.DKGRAY);
textAppearance = types.getResourceId(R.styleable.OField_fieldTextAppearance, -1);
labelAppearance = types.getResourceId(R.styleable.OField_fieldLabelTextAppearance, -1);
textSize = types.getDimension(R.styleable.OField_fieldTextSize, -1);
labelSize = types.getDimension(R.styleable.OField_fieldLabelSize, -1);
defaultImage = types.getResourceId(R.styleable.OField_defaultImage, -1);
types.recycle();
}
if (mContext.getClass().getSimpleName().contains("BridgeContext"))
initControl();
}
public void useTemplate(Boolean withTemplate) {
useTemplate = withTemplate;
}
private void initLayout() {
removeAllViews();
if (useTemplate) {
View layout = LayoutInflater.from(mContext).inflate(
R.layout.base_control_template, this, false);
if (withPadding) {
int top_padding = layout.getPaddingTop();
int right_padding = layout.getPaddingRight();
int bottom_padding = layout.getPaddingBottom();
int left_padding = layout.getPaddingLeft();
if (!with_bottom_padding) {
layout.setPadding(left_padding, top_padding, right_padding, 0);
}
if (!with_top_padding) {
layout.setPadding(left_padding, 0, right_padding, bottom_padding);
}
} else {
layout.setPadding(0, 0, 0, 0);
}
addView(layout);
container = (ViewGroup) findViewById(R.id.control_container);
img_icon = (ImageView) findViewById(android.R.id.icon);
img_icon.setColorFilter(tint_color);
setImageIcon();
} else {
container = this;
}
}
public void initControl() {
initLayout();
View controlView = null;
if (show_label) {
label_view = getLabelView();
container.addView(label_view);
}
switch (mType) {
case Text:
controlView = initTextControl();
break;
case Boolean:
controlView = initBooleanControl();
break;
case Chips:
break;
case ManyToOne:
case Selection:
controlView = initSelectionWidget();
break;
case Date:
case Time:
case DateTime:
controlView = initDateTimeControl(mType);
break;
case Blob:
controlView = initBlobControl();
break;
default:
return;
}
mControlData.setValueUpdateListener(this);
mControlData.setEditable(getEditable());
mControlData.initControl();
mControlData.setValue(mValue);
container.addView(controlView);
}
public <T> T getFieldView() {
return (T) mControlData.getFieldView();
}
public void setIconTintColor(int color) {
tint_color = color;
if (img_icon != null) {
img_icon.setColorFilter(tint_color);
}
}
private void setImageIcon() {
if (showIcon) {
if (resId != 0)
img_icon.setImageResource(resId);
if (tint_color != 0)
img_icon.setColorFilter(tint_color);
} else
img_icon.setVisibility(View.GONE);
}
public <T> void setColumn(OColumn column) {
mColumn = column;
mType = getType(column.getType());
if (label_view != null) {
label_view.setText(getLabelText());
}
if (mControlData != null) {
mControlData.setColumn(mColumn);
}
}
private <T> FieldType getType(Class<T> type_class) {
try {
// Varchar
if (type_class.isAssignableFrom(OVarchar.class)
|| type_class.isAssignableFrom(OInteger.class)
|| type_class.isAssignableFrom(OFloat.class)) {
return FieldType.Text;
}
// boolean
if (type_class.isAssignableFrom(OBoolean.class)) {
return FieldType.Boolean;
}
// Blob
if (type_class.isAssignableFrom(OBlob.class)) {
return FieldType.Blob;
}
// DateTime
if (type_class.isAssignableFrom(ODateTime.class)
|| type_class.isAssignableFrom(OTimestamp.class)) {
return FieldType.DateTime;
}
// Date
if (type_class.isAssignableFrom(ODate.class)) {
return FieldType.Date;
}
// Text
if (type_class.isAssignableFrom(OText.class)) {
return FieldType.Text;
}
// FIXME: WebView type
if (type_class.isAssignableFrom(OHtml.class)) {
return FieldType.Text;
}
if (type_class.isAssignableFrom(OSelection.class)) {
return FieldType.Selection;
}
// ManyToOne
if (mColumn.getRelationType() != null
&& mColumn.getRelationType() == OColumn.RelationType.ManyToOne) {
return FieldType.ManyToOne;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getLabelText() {
if (mLabel != null)
return mLabel;
if (mColumn != null)
return mColumn.getLabel();
if (mControlData != null)
return mControlData.getLabel();
return getFieldName();
}
public void setValue(Object value) {
mValue = value;
if (mValue != null && mControlData != null) {
mControlData.setValue(mValue);
}
}
public Object getValue() {
if (mControlData != null)
return mControlData.getValue();
return null;
}
public void setEditable(Boolean editable) {
mEditable = editable;
if (mControlData != null) {
Object value = getValue();
mControlData.setEditable(editable);
mControlData.initControl();
if (value != null)
mControlData.setValue(value);
}
}
public boolean getEditable() {
return mEditable;
}
public String getFieldName() {
return mField_name;
}
// EditText control (TextView, EditText)
private View initTextControl() {
setOrientation(VERTICAL);
OEditTextField edt = new OEditTextField(mContext);
edt.setWidgetType(mWidgetType);
mControlData = edt;
edt.setResource(textSize, textAppearance, textColor);
edt.setColumn(mColumn);
edt.setHint(mLabel);
return edt;
}
// Boolean Control (Checkbox, W-Switch)
private View initBooleanControl() {
OBooleanField bool = new OBooleanField(mContext);
mControlData = bool;
bool.setResource(textSize, textAppearance, textColor);
bool.setColumn(mColumn);
bool.setEditable(getEditable());
bool.setLabelText(getLabelText());
bool.setWidgetType(mWidgetType);
return bool;
}
// Selection, Searchable, SearchableLive
private View initSelectionWidget() {
OSelectionField selection = new OSelectionField(mContext);
mControlData = selection;
selection.setResource(textSize, textAppearance, textColor);
selection.setLabelText(getLabelText());
selection.setModel(mModel);
selection.setArrayResourceId(mValueArrayId);
selection.setColumn(mColumn);
selection.setWidgetType(mWidgetType);
return selection;
}
// Datetime (dialog with date or date time)
private View initDateTimeControl(FieldType type) {
ODateTimeField datetime = new ODateTimeField(mContext);
mControlData = datetime;
datetime.setResource(textSize, textAppearance, textColor);
datetime.setFieldType(type);
datetime.setParsePattern(mParsePattern);
datetime.setLabelText(getLabelText());
datetime.setColumn(mColumn);
return datetime;
}
// Blob (file contents)
private View initBlobControl() {
OBlobField blob = new OBlobField(mContext);
mControlData = blob;
blob.setDefaultImage(defaultImage);
blob.setImageSize(mWidgetImageSize);
blob.setLabelText(getLabelText());
blob.setColumn(mColumn);
blob.setWidgetType(mWidgetType);
return blob;
}
private TextView getLabelView() {
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
TextView label = new TextView(mContext);
if (labelSize > -1) {
label.setTextSize(TypedValue.COMPLEX_UNIT_PX, labelSize);
}
if (labelAppearance > -1) {
label.setTextAppearance(mContext, labelAppearance);
}
label.setTextColor(labelColor);
label.setLayoutParams(params);
label.setGravity(Gravity.LEFT);
label.setText(getLabelText());
label.setAllCaps(true);
return label;
}
public void setIcon(int resourceId) {
img_icon.setImageResource(resourceId);
}
public void setError(String error) {
mControlData.setError(error);
}
public int getIcon() {
return resId;
}
public void setModel(OModel model) {
mModel = model;
}
public OModel getModel() {
return mModel;
}
public OColumn getColumn() {
return mColumn;
}
public void resetData() {
mControlData.resetData();
}
@Override
public void onValueUpdate(Object value) {
mValue = value;
if (mValueUpdateListener != null) {
mValueUpdateListener.onFieldValueChange(this, value);
}
if (value instanceof ODataRow) {
mValue = ((ODataRow) value).get(OColumn.ROW_ID);
}
if (mEditable) {
if (mControlData.isControlReady()) {
ODataRow row = new ODataRow();
if (mOnChangeCallback != null
|| mOnDomainFilterCallbacks != null) {
if (!(value instanceof ODataRow)) {
row.put(mColumn.getName(), value);
} else {
row = (ODataRow) value;
}
}
if (mOnChangeCallback != null) {
mOnChangeCallback.onValueChange(row);
}
if (mOnDomainFilterCallbacks != null) {
mColumnDomain.setValue(row.getInt(OColumn.ROW_ID));
mOnDomainFilterCallbacks.onFieldValueChanged(mColumnDomain);
}
}
}
}
public void setOnValueChangeListener(IOnFieldValueChangeListener listener) {
mValueUpdateListener = listener;
}
@Override
public void visibleControl(boolean isVisible) {
if (isVisible) {
setVisibility(View.VISIBLE);
} else {
setVisibility(View.GONE);
}
}
/**
* OnChange CallBack for column
*
* @param callback
*/
public void setOnChangeCallbackListener(IOnChangeCallback callback) {
mOnChangeCallback = callback;
}
/**
* Domain Filters
*
* @param domain
* @param callback
*/
public void setOnFilterDomainCallBack(OColumn.ColumnDomain domain,
IOnDomainFilterCallbacks callback) {
mColumnDomain = domain;
mOnDomainFilterCallbacks = callback;
}
public interface IOnFieldValueChangeListener {
public void onFieldValueChange(OField field, Object value);
}
}