/*
* 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/>
*
*/
package odoo.controls;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import odoo.controls.MultiTagsTextView.TokenListener;
import odoo.controls.OManyToOneWidget.ManyToOneItemChangeListener;
import odoo.controls.OSearchableMany2One.DialogListRowViewListener;
import odoo.controls.OTagsView.CustomTagViewListener;
import odoo.controls.OTagsView.NewTokenCreateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.odoo.R;
import com.odoo.orm.OColumn;
import com.odoo.orm.OColumn.ColumnDomain;
import com.odoo.orm.OColumn.RelationType;
import com.odoo.orm.ODataRow;
import com.odoo.orm.OM2ORecord;
import com.odoo.orm.OModel;
import com.odoo.orm.OModel.Command;
import com.odoo.orm.ORelIds;
import com.odoo.orm.types.OBoolean;
import com.odoo.orm.types.ODateTime;
import com.odoo.support.listview.OListAdapter;
import com.odoo.util.Base64Helper;
import com.odoo.util.ODate;
import com.odoo.util.StringUtils;
/**
* The Class OField.
*/
public class OField extends LinearLayout implements
ManyToOneItemChangeListener, TokenListener, CustomTagViewListener {
/** The Constant TAG. */
public static final String TAG = OField.class.getSimpleName();
/** The Constant KEY_EDITABLE. */
public static final String KEY_EDITABLE = "editable";
/** The Constant KEY_WITH_LABEL. */
public static final String KEY_WITH_LABEL = "with_label";
/** The Constant KEY_FIELD_NAME. */
public static final String KEY_FIELD_NAME = "field_name";
/** The Constant KEY_FIELD_TYPE. */
public static final String KEY_FIELD_TYPE = "field_type";
/** The Constant KEY_LABEL_COLOR. */
public static final String KEY_LABEL_COLOR = "label_color";
/** The Constant KEY_FIELD_COLOR. */
public static final String KEY_FIELD_COLOR = "field_color";
/** The Constant KEY_FIELD_STYLE. */
public static final String KEY_FIELD_STYLE = "field_style";
/** The Constant KEY_LABEL_TEXT_APPEARANCE. */
public static final String KEY_LABEL_TEXT_APPEARANCE = "label_text_appearance";
/** The Constant KEY_FIELD_TEXT_APPEARANCE. */
public static final String KEY_FIELD_TEXT_APPEARANCE = "field_text_appearance";
/** The Constant KEY_SINGLE_LINE. */
public static final String KEY_SINGLE_LINE = "singleLine";
/** The Constant KEY_BINARY_TYPE. */
public static final String KEY_BINARY_TYPE = "binaryType";
/** The Constant KEY_DEFAULT_IMAGE. */
public static final String KEY_DEFAULT_IMAGE = "defaultImage";
/** The Constant KEY_BOOLEAN_WIDGET. */
public static final String KEY_BOOLEAN_WIDGET = "booleanWidget";
/** The Constant KEY_CUSTOM_LAYOUT. */
public static final String KEY_CUSTOM_LAYOUT = "customLayout";
/** The Constant KEY_BOTTOM_BORDER_HEIGHT. */
public static final String KEY_BOTTOM_BORDER_HEIGHT = "bottom_border_height";
/** The Constant KEY_TEXT_LINES. */
public static final String KEY_TEXT_LINES = "textLines";
/** The Constant KEY_REF_COLUMN. */
public static final String KEY_REF_COLUMN = "ref_column";
/** The Constant KEY_SHOW_AS_TEXT. */
public static final String KEY_SHOW_AS_TEXT = "showAsText";
/** The Constant KEY_DISPLAY_PATTERN. */
public static final String KEY_DISPLAY_PATTERN = "displayPattern";
/** The Constant KEY_ROUND_IMAGE_WIDTH_HEIGHT. */
public static final String KEY_ROUND_IMAGE_WIDTH_HEIGHT = "imageWidthHeight";
/** The Constant KEY_CUSTOM_LAYOUT_ORIANTATION. */
public static final String KEY_CUSTOM_LAYOUT_ORIANTATION = "customLayoutOriantation";
/** The Constant KEY_READ_MORE_BUTTON. */
public static final String KEY_READ_MORE_BUTTON = "readMoreButton";
public static final String KEY_WIDGET = "widget";
public static final String KEY_WIDGET_TITLE = "widgetTitle";
/**
* Parent view. Updated for new UI look for API 21+
*/
private LinearLayout mParent = null;
/**
* The Enum OFieldMode.
*/
enum OFieldMode {
/** The editable. */
EDITABLE,
/** The readonly. */
READONLY
}
/**
* The Enum TextStyle.
*/
public enum TextStyle {
/** The bold. */
BOLD,
/** The normal. */
NORMAL
}
/**
* The Enum OFieldType.
*/
public enum OFieldType {
/** The many to one. */
MANY_TO_ONE, MANY_TO_ONE_SEARCHABLE,
/** The many to many tags. */
MANY_TO_MANY_TAGS,
/** The binary. */
BINARY,
/** The binary image. */
BINARY_IMAGE,
/** The binary rounded image. */
BINARY_ROUND_IMAGE,
/** The binary file. */
BINARY_FILE,
/** The boolean widget. */
BOOLEAN_WIDGET,
/** The boolean checkbox. */
BOOLEAN_CHECKBOX,
/** The boolean switch. */
BOOLEAN_SWITCH,
/** The boolean radio. */
BOOLEAN_RADIO,
/** The web view. */
WEB_VIEW
}
/** The context. */
private Context mContext = null;
/** The typed array. */
private TypedArray mTypedArray = null;
/** The field value. */
private Object mFieldValue = null;
/** The model used with widget controls. */
private OModel mModel = null;
/** The control record. */
private ODataRow mControlRecord = null;
/** The column object. */
private OColumn mColumn = null;
/** The control attributes. */
private OControlAttributes mAttributes = new OControlAttributes();
/** The control field type. */
private OFieldMode mFieldType = OFieldMode.READONLY;
/** The field widget if any. */
private OFieldType mFieldWidget = null;
/** The layout params. */
private LayoutParams mLayoutParams = null;
/** The field label. */
private OLabel mFieldLabel = null;
/** The field text view. */
private TextView mFieldTextView = null;
/** The field edit text. */
private EditText mFieldEditText = null;
/** The many to one widget. */
private OManyToOneWidget mManyToOne = null;
private OSearchableMany2One mManyToOneSearchable = null;
private DialogListRowViewListener mDialogListRowViewListener = null;
/** The many to many tags. */
private OTagsView mManyToManyTags = null;
/** The many to many adapter. */
private OListAdapter mManyToManyAdapter = null;
/** The many to many records. */
private List<Object> mM2MRecords = new ArrayList<Object>();
/** The new added records. */
private HashMap<String, ODataRow> mM2MAddedRecords = new HashMap<String, ODataRow>();
/** The removed records. */
private HashMap<String, ODataRow> mM2MRemovedRecords = new HashMap<String, ODataRow>();
/** The m many to many object editable. */
private Boolean mManyToManyObjectEditable = true;
/** The radio group. */
private RadioGroup mRadioGroup = null;
/** The true radio button. */
private RadioButton mTrueRadioButton = null;
/** The false radio button. */
private RadioButton mFalseRadioButton = null;
/** The check box. */
private CheckBox mCheckBox = null;
/** The switch. */
private Switch mSwitch = null;
/** The web view. */
private OWebTextView mWebView = null;
/** The display metrics. */
private DisplayMetrics mMetrics = null;
/** The scale factor. */
private Float mScaleFactor = 0F;
private OForm.OnViewClickListener mOForm_OnViewClickListener = null;
private boolean autoUpdateUI = false;
/**
* Used for handling onChange of Control (if any)
*/
private OnChangeCallback mOnChangeCallBack = null;
/**
* Used to filter data depends on another column at runtime
*/
private OnDomainFilterCallbacks mOnDomainFilterCallbacks = null;
private ColumnDomain mColumnDomain = null;
/**
* Instantiates a new field.
*
* @param context
* the context
*/
public OField(Context context) {
super(context);
init(context, null, 0);
}
/**
* Instantiates a new field.
*
* @param context
* the context
* @param attrs
* the attrs
*/
public OField(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
/**
* Instantiates a new field.
*
* @param context
* the context
* @param attrs
* the attrs
* @param defStyle
* the def style
*/
public OField(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
public void setAutoUpdateUI(Boolean autoUpdate) {
autoUpdateUI = autoUpdate;
}
/**
* Inits the control.
*
* @param context
* the context
* @param attrs
* the attrs
* @param defStyle
* the def style
*/
private void init(Context context, AttributeSet attrs, int defStyle) {
mContext = context;
mMetrics = getResources().getDisplayMetrics();
mScaleFactor = mMetrics.density;
if (attrs != null) {
mTypedArray = mContext.obtainStyledAttributes(attrs,
R.styleable.OField);
initAttributeValues();
mTypedArray.recycle();
}
if (mAttributes.size() > 0)
setTag("field_tag_" + mAttributes.getString(KEY_FIELD_NAME, ""));
}
/**
* Re init the control.
*/
public void reInit() {
if (getTag() == null)
setTag("field_tag_" + mAttributes.getString(KEY_FIELD_NAME, ""));
initControls();
}
/**
* Inits the controls.
*/
private void initControls() {
removeAllViews();
setOrientation(LinearLayout.VERTICAL);
setLayoutUI();
createLabel();
if (mFieldWidget == null) {
createTextViewControl();
} else {
createWidget(mFieldWidget);
}
}
private void setLayoutUI() {
if (autoUpdateUI) {
int padd = (int) (mScaleFactor * 10);
if (!withLabel()) {
setPadding(padd, 5, padd, 5);
} else
setPadding(padd, padd, padd, padd);
setBackgroundColor(Color.WHITE);
post(new Runnable() {
@Override
public void run() {
LayoutParams params = (LayoutParams) getLayoutParams();
int margin = (int) (mScaleFactor * 5);
if (withLabel()) {
params.setMargins(margin, margin, margin, 0);
} else {
params.setMargins(margin, 0, margin, 0);
}
setLayoutParams(params);
}
});
}
}
/**
* Creates the widget.
*
* @param fieldWidget
* the field widget
*/
private void createWidget(OFieldType fieldWidget) {
switch (fieldWidget) {
case MANY_TO_ONE:
createManyToOneWidget();
break;
case MANY_TO_ONE_SEARCHABLE:
createManyToOneSearchable();
break;
case BINARY_FILE:
case BINARY_IMAGE:
createBinaryControl(fieldWidget, false);
break;
case BINARY_ROUND_IMAGE:
createBinaryControl(fieldWidget, true);
break;
case BOOLEAN_WIDGET:
case BOOLEAN_CHECKBOX:
case BOOLEAN_RADIO:
case BOOLEAN_SWITCH:
createBooleanControl(fieldWidget);
break;
case WEB_VIEW:
createWebView();
break;
case MANY_TO_MANY_TAGS:
createManyToManyTags();
break;
default:
break;
}
}
/**
* Sets the object editable.
*
* @param editable
* the editable
* @return the o field
*/
public OField setObjectEditable(Boolean editable) {
mManyToManyObjectEditable = editable;
return this;
}
public boolean isEditable() {
return (mAttributes.getBoolean(KEY_EDITABLE, false));
}
/**
* Creates the many to many tags.
*/
private void createManyToManyTags() {
List<ODataRow> records = new ArrayList<ODataRow>();
if (mControlRecord != null) {
if (mColumn.getRelationType() == RelationType.OneToMany) {
records.addAll(mControlRecord.getO2MRecord(mColumn.getName())
.browseEach());
} else {
records.addAll(mControlRecord.getM2MRecord(mColumn.getName())
.browseEach());
}
}
String ref_column = mAttributes.getString(KEY_REF_COLUMN, "name");
int customLayoutOriantation = mAttributes.getResource(
KEY_CUSTOM_LAYOUT_ORIANTATION, -1);
int custom_layout = mAttributes.getResource(KEY_CUSTOM_LAYOUT, -1);
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
LinearLayout mlayout = new LinearLayout(mContext);
mlayout.setLayoutParams(mLayoutParams);
if (customLayoutOriantation == 1)
mlayout.setOrientation(LinearLayout.VERTICAL);
else
mlayout.setOrientation(LinearLayout.HORIZONTAL);
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
List<ODataRow> mSelectedObjects = new ArrayList<ODataRow>();
mSelectedObjects.addAll(records);
List<Integer> ids = new ArrayList<Integer>();
for (ODataRow r : mSelectedObjects) {
ids.add(r.getInt(OColumn.ROW_ID));
}
records.clear();
String whr = null;
Object[] args = null;
if (ids.size() > 0) {
whr = OColumn.ROW_ID + " NOT IN ("
+ StringUtils.repeat(" ?, ", ids.size() - 1) + "?)";
args = new Object[] { ids };
}
if (mManyToManyObjectEditable)
records.addAll(mModel.select(whr, args));
records.addAll(mSelectedObjects);
mManyToManyTags = new OTagsView(mContext);
mManyToManyTags.setCustomTagView(this);
mManyToManyTags.setTypeface(OControlHelper.lightFont());
mManyToManyTags.setHintTextColor(mContext.getResources().getColor(
R.color.gray_text));
mManyToManyTags.setHint(mColumn.getLabel());
mManyToManyTags
.setAdapter(getManyToManyAdapter(records, ref_column));
mManyToManyTags.setTokenListener(this);
mManyToManyTags.allowDuplicates(false);
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
mManyToManyTags.setLayoutParams(mLayoutParams);
for (ODataRow row : mSelectedObjects) {
mManyToManyTags.addObject(row);
}
mlayout.addView(mManyToManyTags);
addView(mlayout);
} else {
if (mControlRecord != null) {
if (records.size() > 0) {
for (ODataRow row : records) {
if (custom_layout > -1) {
LinearLayout rowView = (LinearLayout) getManyToManyRowView(row);
mlayout.addView(rowView);
} else {
TextView mtag = new TextView(mContext);
mLayoutParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
mLayoutParams.setMargins(5, 0, 5, 5);
mtag.setLayoutParams(mLayoutParams);
mtag.setPadding(5, 8, 5, 8);
mtag.setSingleLine(true);
mtag.setText(row.getString(ref_column));
mtag.setBackgroundColor(Color.LTGRAY);
mtag.setTypeface(OControlHelper.boldFont());
mlayout.addView(mtag);
}
}
switch (customLayoutOriantation) {
case 1: // vertical
LinearLayout mParentLayout = new LinearLayout(mContext);
mParentLayout.setLayoutParams(mLayoutParams);
mParentLayout.setOrientation(LinearLayout.VERTICAL);
mParentLayout.addView(mlayout);
addView(mParentLayout);
break;
case 0: // horizontal
default:
HorizontalScrollView mHScroll = new HorizontalScrollView(
mContext);
mHScroll.setLayoutParams(mLayoutParams);
mHScroll.setHorizontalScrollBarEnabled(false);
mHScroll.addView(mlayout);
addView(mHScroll);
break;
}
} else {
// No any record.
createTextViewControl();
setText("No " + mColumn.getLabel());
}
}
}
}
private View getManyToManyRowView(final ODataRow row) {
int custom_layout = mAttributes.getResource(KEY_CUSTOM_LAYOUT, -1);
if (custom_layout > -1) {
LayoutInflater inflater = LayoutInflater.from(mContext);
final OForm form = (OForm) inflater.inflate(custom_layout, null);
form.initForm(row);
if (mOForm_OnViewClickListener != null) {
form.setClickable(true);
form.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
form.setId(getId());
mOForm_OnViewClickListener.onFormViewClick(form, row);
}
});
}
return form;
} else {
throw new NullPointerException("No Custom layout found for field "
+ mColumn.getName() + " (" + mColumn.getLabel() + ")");
}
}
@Override
public View getViewForTags(LayoutInflater layoutInflater, Object object,
ViewGroup tagsViewGroup) {
return getManyToManyRowView((ODataRow) object);
}
private OListAdapter getManyToManyAdapter(List<ODataRow> records,
final String ref_column) {
mM2MRecords.clear();
mM2MRecords.addAll(records);
mManyToManyAdapter = new OListAdapter(mContext, 0, mM2MRecords) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = getManyToManyRowView((ODataRow) mM2MRecords
.get(position));
return (v != null) ? v : super.getView(position, convertView,
parent);
}
};
mManyToManyAdapter
.setRowFilterTextListener(new OListAdapter.RowFilterTextListener() {
@Override
public String filterCompareWith(Object object) {
ODataRow row = (ODataRow) object;
return row.getString(ref_column);
}
});
return mManyToManyAdapter;
}
@Override
public void onTokenAdded(Object token, View view) {
if (token != null && mManyToManyObjectEditable) {
ODataRow row = (ODataRow) token;
String key = "KEY_" + row.getString(OColumn.ROW_ID);
mM2MAddedRecords.put(key, row);
if (mM2MRemovedRecords.containsKey(key)) {
mM2MRemovedRecords.remove(key);
}
}
}
@Override
public void onTokenSelected(Object token, View view) {
}
@Override
public void onTokenRemoved(Object token) {
if (token != null && mManyToManyObjectEditable) {
ODataRow row = (ODataRow) token;
String key = "KEY_" + row.getString(OColumn.ROW_ID);
if (mM2MAddedRecords.containsKey(key)) {
mM2MAddedRecords.remove(key);
}
mM2MRemovedRecords.put(key, row);
} else {
mManyToManyTags.addObject(token);
}
}
/**
* Creates the web view.
*/
private void createWebView() {
boolean showAsText = mAttributes.getBoolean(KEY_SHOW_AS_TEXT, false);
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
createTextViewControl();
if (mControlRecord != null) {
setText(mControlRecord.getString(mColumn.getName()));
}
} else {
if (mControlRecord != null) {
if (!showAsText) {
String content = mControlRecord
.getString(mColumn.getName());
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
mWebView = new OWebTextView(mContext);
mWebView.setLayoutParams(mLayoutParams);
if (content.equals("false")) {
content = "";
} else if (withReadMoreButton()) {
mWebView.setLines(5);
mWebView.setMaxLines(5);
}
mWebView.setPadding(mWebView.getPaddingLeft(),
mWebView.getPaddingTop(),
mWebView.getPaddingRight(),
(int) (10 * mScaleFactor));
mWebView.setTextAppearance(mContext,
android.R.attr.textAppearanceSmall);
mWebView.setHtmlContent(content);
mWebView.setBackgroundColor(Color.TRANSPARENT);
addView(mWebView);
addReadMoreButton(content);
} else {
createTextViewControl();
setText(StringUtils.htmlToString(mControlRecord
.getString(mColumn.getName())));
}
}
}
}
private boolean withReadMoreButton() {
return mAttributes.getBoolean(KEY_READ_MORE_BUTTON, false);
}
private void addReadMoreButton(final String content) {
if (withReadMoreButton() && !TextUtils.isEmpty(mWebView.getText())) {
final TextView txvReadMore = new TextView(mContext);
txvReadMore.setGravity(Gravity.CENTER);
txvReadMore.setTextAppearance(mContext,
android.R.attr.textAppearanceMedium);
txvReadMore.setTypeface(OControlHelper.boldFont());
txvReadMore.setText(R.string.label_read_more);
txvReadMore.setAllCaps(true);
int padd = (int) (10 * mScaleFactor);
txvReadMore.setPadding(padd, padd, padd, padd);
txvReadMore.setClickable(true);
txvReadMore.setTextColor(mContext.getResources().getColor(
R.color.odoo_purple));
txvReadMore
.setBackgroundResource(R.drawable.oe_background_selector);
txvReadMore.setTag("more");
txvReadMore.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TextView txv = (TextView) v;
if (v.getTag().toString().equals("more")) {
mWebView.setLines(mWebView.getLineCount());
mWebView.setMaxLines(mWebView.getLineCount());
txv.setText(R.string.label_read_less);
v.setTag("less");
} else {
v.setTag("more");
txv.setText(R.string.label_read_more);
mWebView.setLines(5);
mWebView.setMaxLines(5);
}
}
});
mWebView.setOnLayoutLoad(new OWebTextView.OnLayoutLoad() {
@Override
public void layoutLoad(OWebTextView view) {
new Handler().post(new Runnable() {
@Override
public void run() {
int lines = mWebView.getLineCount();
if (lines < 5) {
mWebView.setLines(lines);
mWebView.setMaxLines(lines);
mWebView.postInvalidate();
txvReadMore.setVisibility(View.GONE);
}
}
});
}
});
addView(txvReadMore);
}
}
/**
* Creates the boolean control.
*
* @param fieldWidget
* the field widget
*/
private void createBooleanControl(OFieldType fieldWidget) {
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
Boolean val = (mControlRecord != null) ? mControlRecord
.getBoolean(mColumn.getName()) : false;
switch (fieldWidget) {
case BOOLEAN_CHECKBOX:
mCheckBox = new CheckBox(mContext);
mCheckBox.setLayoutParams(mLayoutParams);
mCheckBox.setText(mColumn.getLabel());
mCheckBox.setChecked(val);
addView(mCheckBox);
break;
case BOOLEAN_RADIO:
mRadioGroup = new RadioGroup(mContext);
mRadioGroup.setLayoutParams(mLayoutParams);
mRadioGroup.setOrientation(RadioGroup.HORIZONTAL);
mLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
mTrueRadioButton = new RadioButton(mContext);
mTrueRadioButton.setLayoutParams(mLayoutParams);
mTrueRadioButton.setText("True");
mTrueRadioButton.setId(0x1234 + (int) Math.random());
if (val)
mTrueRadioButton.setChecked(val);
mTrueRadioButton.setTag("true_widget");
mRadioGroup.addView(mTrueRadioButton);
mFalseRadioButton = new RadioButton(mContext);
mFalseRadioButton.setLayoutParams(mLayoutParams);
mFalseRadioButton.setText("False");
mFalseRadioButton.setId(0x4321 + (int) Math.random());
if (!val)
mFalseRadioButton.setChecked(!val);
mFalseRadioButton.setTag("false_widget");
mRadioGroup.addView(mFalseRadioButton);
addView(mRadioGroup);
break;
case BOOLEAN_SWITCH:
mLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
mLayoutParams.setMargins(0, 8, 0, 8);
mSwitch = new Switch(mContext);
mSwitch.setLayoutParams(mLayoutParams);
mSwitch.setTextOn("True");
mSwitch.setTextOff("False");
mSwitch.setChecked(val);
addView(mSwitch);
break;
default:
break;
}
} else {
createTextViewControl();
if (mControlRecord != null) {
String value = mControlRecord.getString(mColumn.getName());
setText(value);
}
}
}
/**
* Creates the binary control.
*
* @param binary_type
* the binary_type
* @param roundedImage
* the rounded image
*/
private void createBinaryControl(final OFieldType binary_type,
final boolean roundedImage) {
final ImageView imgBinary;
if (roundedImage) {
imgBinary = new BezelImageView(mContext);
imgBinary.setScaleType(ScaleType.CENTER_CROP);
((BezelImageView) imgBinary).autoSetMaskDrawable();
} else {
imgBinary = new ImageView(mContext);
}
int heightWidth = mAttributes.getResource(KEY_ROUND_IMAGE_WIDTH_HEIGHT,
-1);
if (heightWidth > -1) {
heightWidth = (int) (heightWidth * mScaleFactor);
mLayoutParams = new LayoutParams(heightWidth, heightWidth);
imgBinary.setLayoutParams(mLayoutParams);
}
final int default_image = mAttributes.getResource(KEY_DEFAULT_IMAGE,
R.drawable.attachment);
final Bitmap binary_image = BitmapFactory.decodeResource(mContext
.getResources(), (default_image < 0) ? R.drawable.attachment
: default_image);
ODataRow record = null;
String column_name = getRefColumn();
if (mControlRecord != null) {
if (column_name != null) {
if (mColumn.getRelationType() == RelationType.ManyToOne) {
record = mControlRecord.getM2ORecord(mColumn.getName())
.browse();
}
} else {
record = mControlRecord;
if (mColumn != null)
column_name = mColumn.getName();
else {
column_name = mAttributes.getString(KEY_FIELD_NAME, null);
}
}
}
switch (binary_type) {
case BINARY_FILE:
imgBinary
.setImageResource((default_image < 0) ? R.drawable.attachment
: default_image);
break;
case BINARY_ROUND_IMAGE:
case BINARY_IMAGE:
Bitmap newBitmap = binary_image;
if (record != null
&& !record.getString(column_name).equals("false")
&& !record.getString(column_name).equals("null")
&& !record.getString(column_name).equals("0")) {
newBitmap = Base64Helper.getBitmapImage(mContext,
record.getString(column_name));
if (!roundedImage)
imgBinary.setScaleType(ScaleType.CENTER_CROP);
}
imgBinary.setImageBitmap(newBitmap);
break;
default:
break;
}
addView(imgBinary);
}
/**
* Creates the many to one widget.
*/
private void createManyToOneWidget() {
String ref_column = mAttributes.getString(KEY_REF_COLUMN, "name");
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mManyToOne = new OManyToOneWidget(mContext);
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
mManyToOne.setLayoutParams(mLayoutParams);
mManyToOne.setModel(mModel, ref_column, mColumn.getDomains());
int custom_layout = mAttributes.getResource(KEY_CUSTOM_LAYOUT, -1);
if (custom_layout != -1)
mManyToOne.setCustomLayout(custom_layout);
if (mControlRecord != null)
mManyToOne.setRecordId((Integer) mControlRecord.getM2ORecord(
mColumn.getName()).getId());
mManyToOne.reInit();
addView(mManyToOne);
mManyToOne.setOnManyToOneItemChangeListener(this);
} else {
createTextViewControl();
if (mControlRecord != null) {
if (mControlRecord.get(mColumn.getName()) instanceof OM2ORecord) {
ODataRow row = mControlRecord.getM2ORecord(
mColumn.getName()).browse();
if (row != null)
setText(row.getString(ref_column));
else
setText("No " + mColumn.getLabel());
} else {
Integer id = mControlRecord.getInt(mColumn.getName());
if (id != null && id > 0 && ref_column != null) {
mControlRecord.put(mColumn.getName(), mModel.select(id)
.getString(ref_column));
}
setText(mControlRecord.getString(mColumn.getName()));
}
}
}
}
public String getWidgetTitle() {
return mAttributes.getString(KEY_WIDGET_TITLE, "");
}
// TODO
private void createManyToOneSearchable() {
mFieldWidget = OFieldType.MANY_TO_ONE_SEARCHABLE;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mManyToOneSearchable = new OSearchableMany2One(mContext);
mManyToOneSearchable.setLayoutParams(params);
mManyToOneSearchable.setTitle(getWidgetTitle());
mManyToOneSearchable.setModel(mModel);
mManyToOneSearchable.setDefaultDomain(mColumn.getDomains());
mManyToOneSearchable.setOnChangeCallback(mOnChangeCallBack);
mManyToOneSearchable.setOnFilterDomainCallBack(mColumnDomain,
mOnDomainFilterCallbacks);
int custom_layout = mAttributes.getResource(KEY_CUSTOM_LAYOUT, -1);
if (custom_layout > -1) {
mManyToOneSearchable.setDisplayLayout(custom_layout);
}
if (mDialogListRowViewListener != null) {
mManyToOneSearchable
.setDialogListRowViewListener(mDialogListRowViewListener);
}
if (mControlRecord != null
&& mControlRecord.contains(mColumn.getName())) {
ODataRow mrec = mControlRecord.getM2ORecord(mColumn.getName())
.browse();
mManyToOneSearchable.setRecord(mrec);
}
mManyToOneSearchable
.reInit(mAttributes.getBoolean(KEY_EDITABLE, false));
addView(mManyToOneSearchable);
}
public void setManyToOneSearchableCallbacks(
DialogListRowViewListener callback) {
mDialogListRowViewListener = callback;
}
public void selectManyToOneRecord(int row_id) {
if (mManyToOne != null) {
mManyToOne.setRecordId(row_id);
mManyToOne.reInit();
}
}
public boolean withLabel() {
return (mAttributes.getBoolean(KEY_WITH_LABEL, true));
}
/**
* Creates the label.
*/
private void createLabel() {
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
if (mAttributes.getBoolean(KEY_WITH_LABEL, true)) {
mFieldLabel = new OLabel(mContext);
mFieldLabel.setLayoutParams(mLayoutParams);
mFieldLabel.setBottomBorderHeight(0);// mAttributes.getResource(KEY_BOTTOM_BORDER_HEIGHT,
// 0));
if (mColumn != null) {
mFieldLabel.setLabel(mColumn.getLabel());
} else {
mFieldLabel.setLabel(mAttributes.getString(KEY_FIELD_NAME, ""));
}
Integer mAttrLabelTextAppearnce = mAttributes.getResource(
KEY_LABEL_TEXT_APPEARANCE, 2);
if (mAttrLabelTextAppearnce != 0)
mFieldLabel.setTextAppearance(mAttrLabelTextAppearnce);
mFieldLabel.setColor(mAttributes.getColor(KEY_LABEL_COLOR,
Color.BLACK));
addView(mFieldLabel);
}
mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
if (mAttributes.getBoolean(KEY_WITH_LABEL, true))
mLayoutParams.setMargins(0, 5, 0, 5);
}
/**
* Sets the column.
*
* @param column
* the new column
*/
public void setColumn(OColumn column) {
mColumn = column;
}
/**
* Creates the text view control.
*/
private void createTextViewControl() {
Integer mAttrFieldTextAppearnce = mAttributes.getResource(
KEY_FIELD_TEXT_APPEARANCE, 0);
Integer mAttrFieldStyle = mAttributes.getResource(KEY_FIELD_STYLE, 0);
Boolean mSingleLine = mAttributes.getBoolean(KEY_SINGLE_LINE, false);
if (mColumn != null && mColumn.isFunctionalColumn()) {
mAttributes.put(KEY_EDITABLE, false);
}
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText = new EditText(mContext);
mFieldEditText.setLayoutParams(mLayoutParams);
if (mAttrFieldTextAppearnce != 0) {
mFieldEditText.setTextAppearance(mContext,
mAttrFieldTextAppearnce);
}
mFieldEditText.setTextColor(mAttributes.getColor(KEY_FIELD_COLOR,
Color.BLACK));
mFieldEditText.setHint(mAttributes.getString(KEY_FIELD_NAME, ""));
if (mAttrFieldStyle == Typeface.BOLD
|| mAttrFieldStyle == Typeface.BOLD_ITALIC) {
mFieldEditText.setTypeface(OControlHelper.boldFont(),
mAttrFieldStyle);
} else {
mFieldEditText.setTypeface(OControlHelper.lightFont(),
mAttrFieldStyle);
}
mFieldEditText.setTag(getFieldTag());
if (mSingleLine) {
mFieldEditText.setSingleLine(true);
}
addView(mFieldEditText);
} else {
mFieldTextView = new TextView(mContext);
mFieldTextView.setLayoutParams(mLayoutParams);
if (mAttrFieldTextAppearnce != 0) {
mFieldTextView.setTextAppearance(mContext,
mAttrFieldTextAppearnce);
}
mFieldTextView.setTextColor(mAttributes.getColor(KEY_FIELD_COLOR,
Color.BLACK));
mFieldTextView.setText(mAttributes.getString(KEY_FIELD_NAME, ""));
mFieldTextView.setPadding(5, 5, 5, 5);
if (mAttrFieldStyle == Typeface.BOLD
|| mAttrFieldStyle == Typeface.BOLD_ITALIC) {
mFieldTextView.setTypeface(OControlHelper.boldFont(),
mAttrFieldStyle);
} else {
mFieldTextView.setTypeface(OControlHelper.lightFont(),
mAttrFieldStyle);
}
mFieldTextView.setTag(getFieldTag());
if (mSingleLine) {
mFieldTextView.setSingleLine(true);
mFieldTextView.setEllipsize(TruncateAt.END);
}
Integer textLines = mAttributes.getResource(KEY_TEXT_LINES, -1);
if (textLines > 0) {
mFieldTextView.setLines(textLines);
}
addView(mFieldTextView);
}
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
return mFieldEditText.getText().toString();
} else {
return mFieldTextView.getText().toString();
}
}
/**
* Checks if control value empty.
*
* @return true, if is empty
*/
public boolean isEmpty() {
if (mFieldWidget != null) {
switch (mFieldWidget) {
case MANY_TO_MANY_TAGS:
if (mManyToManyTags.getObjects().size() == 0) {
return true;
}
break;
case WEB_VIEW:
return TextUtils.isEmpty(getValue().toString());
case MANY_TO_ONE:
if (mFieldValue != null)
return ((Integer) mFieldValue == 0);
default:
return false;
}
return false;
} else {
return TextUtils.isEmpty(getValue().toString());
}
}
/**
* Gets the field tag.
*
* @return the field tag
*/
@SuppressLint("DefaultLocale")
public String getFieldTag() {
boolean editable = mAttributes.getBoolean(KEY_EDITABLE, false);
String tag = "odoo_field_" + mAttributes.getString(KEY_FIELD_NAME, "")
+ ((editable) ? "_editable" : "_readonly");
mFieldType = (editable) ? OFieldMode.EDITABLE : OFieldMode.READONLY;
return tag;
}
/**
* Inits the attribute values.
*/
private void initAttributeValues() {
mAttributes.put(KEY_FIELD_NAME,
mTypedArray.getString(R.styleable.OField_field_name));
mAttributes.put(KEY_EDITABLE,
mTypedArray.getBoolean(R.styleable.OField_editable, false));
mAttributes.put(KEY_WITH_LABEL,
mTypedArray.getBoolean(R.styleable.OField_with_label, true));
mAttributes.put(KEY_LABEL_TEXT_APPEARANCE, mTypedArray.getResourceId(
R.styleable.OField_label_textAppearance, 0));
mAttributes.put(KEY_LABEL_COLOR, mTypedArray.getColor(
R.styleable.OField_label_color, Color.BLACK));
mAttributes.put(KEY_FIELD_COLOR, mTypedArray.getColor(
R.styleable.OField_field_color, Color.BLACK));
mAttributes.put(KEY_FIELD_TEXT_APPEARANCE, mTypedArray.getResourceId(
R.styleable.OField_field_textAppearance, 0));
String fieldStyle = mTypedArray
.getString(R.styleable.OField_fieldTextStyle);
if (fieldStyle != null && fieldStyle.contains("bold")) {
if (fieldStyle.contains("italic")) {
mAttributes.put(KEY_FIELD_STYLE, Typeface.BOLD_ITALIC);
} else {
mAttributes.put(KEY_FIELD_STYLE, Typeface.BOLD);
}
} else {
mAttributes.put(KEY_FIELD_STYLE, Typeface.NORMAL);
}
mAttributes.put(KEY_SINGLE_LINE,
mTypedArray.getBoolean(R.styleable.OField_singleLine, false));
mAttributes.put(KEY_BINARY_TYPE,
mTypedArray.getInt(R.styleable.OField_binaryType, -1));
int binaryType = mAttributes.getResource(KEY_BINARY_TYPE, -1);
if (binaryType > -1) {
mFieldWidget = (binaryType == 0 || binaryType == 3) ? (binaryType == 0) ? OFieldType.BINARY_IMAGE
: OFieldType.BINARY_ROUND_IMAGE
: OFieldType.BINARY_FILE;
}
mAttributes.put(KEY_DEFAULT_IMAGE,
mTypedArray.getResourceId(R.styleable.OField_defaultImage, -1));
int booleanType = mTypedArray.getInt(R.styleable.OField_booleanWidget,
-1);
if (booleanType > -1) {
switch (booleanType) {
case 0:
mFieldWidget = OFieldType.BOOLEAN_SWITCH;
break;
case 1:
mFieldWidget = OFieldType.BOOLEAN_RADIO;
break;
case 2:
mFieldWidget = OFieldType.BOOLEAN_CHECKBOX;
break;
}
}
mAttributes.put(KEY_BOOLEAN_WIDGET, booleanType);
mAttributes.put(KEY_CUSTOM_LAYOUT,
mTypedArray.getResourceId(R.styleable.OField_customLayout, -1));
mAttributes.put(KEY_BOTTOM_BORDER_HEIGHT, mTypedArray.getInt(
R.styleable.OField_label_bottom_border_height, 2));
mAttributes.put(KEY_TEXT_LINES,
mTypedArray.getInt(R.styleable.OField_textLines, -1));
mAttributes.put(KEY_REF_COLUMN,
mTypedArray.getString(R.styleable.OField_ref_column));
mAttributes.put(KEY_SHOW_AS_TEXT,
mTypedArray.getBoolean(R.styleable.OField_showAsText, false));
mAttributes.put(KEY_DISPLAY_PATTERN,
mTypedArray.getString(R.styleable.OField_displayPattern));
mAttributes.put(KEY_ROUND_IMAGE_WIDTH_HEIGHT,
mTypedArray.getInt(R.styleable.OField_imageWidthHeight, -1));
mAttributes.put(KEY_CUSTOM_LAYOUT_ORIANTATION, mTypedArray.getInt(
R.styleable.OField_customLayoutOriantation, -1));
mAttributes.put(KEY_READ_MORE_BUTTON, mTypedArray.getBoolean(
R.styleable.OField_readMoreButton, false));
mAttributes.put(KEY_WIDGET,
mTypedArray.getInt(R.styleable.OField_widget, -1));
mAttributes.put(KEY_WIDGET_TITLE,
mTypedArray.getString(R.styleable.OField_widgetTitle));
}
/**
* Gets the field name.
*
* @return the field name
*/
public String getFieldName() {
return mAttributes.getString(KEY_FIELD_NAME, null);
}
/**
* Sets the editable.
*
* @param editable
* the new editable
*/
public void setEditable(boolean editable) {
OFieldMode field_type = (editable) ? OFieldMode.EDITABLE
: OFieldMode.READONLY;
if (field_type != mFieldType) {
mFieldType = (editable) ? OFieldMode.EDITABLE : OFieldMode.READONLY;
mAttributes.put(KEY_EDITABLE, editable);
initControls();
}
}
/**
* Gets the field type.
*
* @return the type
*/
public OFieldMode getType() {
return mFieldType;
}
public void setText(String text) {
text = (text.equals("false")) ? "" : text;
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText.setText(text);
} else {
String displayPattern = mAttributes.getString(KEY_DISPLAY_PATTERN,
null);
if (displayPattern != null
&& mColumn.getType().isAssignableFrom(ODateTime.class)) {
text = ODate.getDate(mContext, text, TimeZone.getDefault()
.getID(), displayPattern);
}
if (mColumn != null) {
if (mColumn.getType().isAssignableFrom(OBoolean.class)) {
if (text.equals("true")) {
text = mColumn.getLabel();
} else {
text = "No " + mColumn.getLabel();
}
}
}
mFieldTextView.setText(text);
}
}
public OFieldType getWidget() {
return mFieldWidget;
}
/**
* Sets the label.
*
* @param label
* the new label
*/
public void setLabel(String label) {
if (mAttributes.getBoolean(KEY_WITH_LABEL, true)) {
mFieldLabel.setLabel(label);
if (mAttributes.getBoolean(KEY_EDITABLE, false)
&& mFieldEditText != null) {
mFieldEditText.setHint(label);
}
}
}
/**
* Sets the text size.
*
* @param size
* the new text size
*/
public void setTextSize(float size) {
size = size * mScaleFactor;
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText.setTextSize(size);
} else {
mFieldTextView.setTextSize(size);
}
}
/**
* Sets the text appearance.
*
* @param appearance
* the new text appearance
*/
public void setTextAppearance(int appearance) {
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText.setTextAppearance(mContext, appearance);
} else {
mFieldTextView.setTextAppearance(mContext, appearance);
}
}
/**
* Sets the text style.
*
* @param style
* the new text style
*/
public void setTextStyle(TextStyle style) {
Typeface tf = (style == TextStyle.BOLD) ? OControlHelper.boldFont()
: OControlHelper.lightFont();
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText.setTypeface(tf);
} else {
mFieldTextView.setTypeface(tf);
}
}
/**
* Sets the error.
*
* @param error
* the new error
*/
public void setError(String error) {
if (error == null)
return;
if (mFieldWidget == null) {
mFieldEditText.setError(error);
mFieldEditText.requestFocus();
} else {
Toast.makeText(mContext, error, Toast.LENGTH_LONG).show();
}
}
/**
* Sets the field name.
*
* @param name
* the new field name
*/
public void setFieldName(String name) {
mAttributes.put(KEY_FIELD_NAME, name);
}
/**
* Show label.
*
* @param withLabel
* the with label
*/
public void showLabel(boolean withLabel) {
mAttributes.put(KEY_WITH_LABEL, withLabel);
}
/**
* Creates the control.
*
* @param type
* the type
* @param column
* the column
* @param record
* the record
*/
public void createControl(OFieldType type, OColumn column, ODataRow record) {
if (type != OFieldType.BINARY && type != OFieldType.BOOLEAN_WIDGET
&& type != OFieldType.WEB_VIEW) {
mFieldWidget = type;
if (column.getType() != null)
mModel = new OModel(mContext, null).createInstance(column
.getType());
}
if (type == OFieldType.WEB_VIEW) {
mFieldWidget = type;
}
mColumn = column;
mControlRecord = record;
initControls();
}
/**
* Gets the value.
*
* @return the value
*/
public Object getValue() {
if (mFieldWidget != null) {
switch (mFieldWidget) {
case BOOLEAN_CHECKBOX:
return mCheckBox.isChecked();
case BOOLEAN_RADIO:
return mTrueRadioButton.isChecked();
case BOOLEAN_SWITCH:
return mSwitch.isChecked();
case MANY_TO_ONE:
return mFieldValue;
case MANY_TO_ONE_SEARCHABLE:
if (mManyToOneSearchable.getValue() != null)
return mManyToOneSearchable.getValue().getInt(
OColumn.ROW_ID);
case MANY_TO_MANY_TAGS:
List<Integer> rIds = new ArrayList<Integer>();
Integer base_record_id = (mControlRecord != null) ? mControlRecord
.getInt(OColumn.ROW_ID) : null;
ORelIds rel_obj = new ORelIds(base_record_id);
for (String key : mM2MAddedRecords.keySet()) {
ODataRow row = mM2MAddedRecords.get(key);
rIds.add(row.getInt(OColumn.ROW_ID));
}
// Added list
Command command = Command.Add;
rel_obj.add(rIds, command);
rIds.clear();
for (String key : mM2MRemovedRecords.keySet()) {
ODataRow row = mM2MRemovedRecords.get(key);
rIds.add(row.getInt(OColumn.ROW_ID));
}
// Removed list
command = Command.Delete;
rel_obj.add(rIds, command);
return rel_obj;
case WEB_VIEW:
return "<p>" + getText().replaceAll("(\r\n|\n)", "<br />")
+ "</p>";
case BINARY_IMAGE:
case BINARY_ROUND_IMAGE:
if (mControlRecord != null
&& mControlRecord.contains(mColumn.getName())) {
return mControlRecord.get(mColumn.getName());
}
return null;
default:
return getText();
}
} else {
return getText();
}
}
/**
* Checks if is dirty field.
*
* @return the boolean
*/
public Boolean isDirtyField() {
if (mFieldWidget != null) {
return mManyToOne.isDirty();
} else {
if (mAttributes.getBoolean(KEY_EDITABLE, false)) {
mFieldEditText.isDirty();
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see odoo.controls.OManyToOneWidget.ManyToOneItemChangeListener#
* onManyToOneItemChangeListener(com.odoo.orm.OColumn,
* com.odoo.orm.ODataRow)
*/
@Override
public void onManyToOneItemChangeListener(OColumn column, ODataRow row) {
mFieldValue = row.get(OColumn.ROW_ID);
}
/**
* Gets the ref column.
*
* @return the ref column
*/
public String getRefColumn() {
return mAttributes.getString(KEY_REF_COLUMN, null);
}
public void setOnItemClickListener(OForm.OnViewClickListener listener) {
mOForm_OnViewClickListener = listener;
}
public void setOnNewTokenCreateListener(NewTokenCreateListener listener) {
if (mManyToManyTags != null)
mManyToManyTags.setNewTokenCreateListener(listener);
}
public void setOnTokenFocusChangeListener(OnFocusChangeListener listener) {
if (mManyToManyTags != null) {
mManyToManyTags.setOnFocusChangeListener(listener);
}
}
public void setTagText(String str) {
if (mManyToManyTags != null) {
mManyToManyTags.setText(str);
}
}
public Object getToken() {
if (mManyToManyTags != null) {
return mManyToManyTags.getText();
}
return null;
}
public void addTagObject(Object tag) {
if (mManyToManyTags != null)
mManyToManyTags.addObject(tag);
}
public void setOnChangeCallBack(OnChangeCallback callback) {
mOnChangeCallBack = callback;
}
public void setOnFilterDomainCallBack(ColumnDomain domain,
OnDomainFilterCallbacks callback) {
mColumnDomain = domain;
mOnDomainFilterCallbacks = callback;
}
public boolean isSearchableWidget() {
return (mAttributes.getResource(KEY_WIDGET, -1) > -1);
}
}