<commit_before>package org.openforis.collect.android.gui.input;

import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatEditText;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.*;
import org.apache.commons.lang3.ObjectUtils;
import org.openforis.collect.R;
import org.openforis.collect.android.CodeListService;
import org.openforis.collect.android.SurveyService;
import org.openforis.collect.android.gui.util.Keyboard;
import org.openforis.collect.android.viewmodel.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author <NAME>
 */
class CheckboxCodeAttributeCollectionComponent extends CodeAttributeCollectionComponent {
    private final SparseArray<UiCode> codeByViewId = new SparseArray<UiCode>();
    private final Map<UiCode, UiCodeAttribute> attributesByCode = new HashMap<UiCode, UiCodeAttribute>();
    private final LinearLayout layout;
    private EditText qualifierInput;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private AtomicBoolean qualified = new AtomicBoolean();

    CheckboxCodeAttributeCollectionComponent(UiAttributeCollection attributeCollection, CodeListService codeListService, SurveyService surveyService, FragmentActivity context) {
        super(attributeCollection, codeListService, surveyService, context);
        layout = new LinearLayout(context);
        layout.setOrientation(LinearLayout.VERTICAL);
        for (UiNode uiNode : attributeCollection.getChildren()) {
            UiCodeAttribute attribute = (UiCodeAttribute) uiNode;
            attributesByCode.put(attribute.getCode(), attribute);
        }
        initOptions();
    }

    public void saveNode() {
        super.saveNode();
        saveQualifier();
    }

    protected Set<UiAttribute> updateChangedAttributes() {
        return new HashSet<UiAttribute>();
    }

    protected View toInputView() {
        return layout;
    }

    public View getDefaultFocusedView() {
        return qualified.get() ? qualifierInput : null;
    }

    // TODO: Dry - same as in AttributeComponent
    protected void setValidationError(UiAttribute attribute, final Set<UiValidationError> validationErrors) {
        uiHandler.post(new Runnable() {
            public void run() {
                if (!isSelected())
                    return;
                TextView labelView = errorMessageContainerView();
                if (validationErrors == null || validationErrors.isEmpty()) {
                    labelView.setError(null);
                    return;
                }
                StringBuilder message = new StringBuilder();
                for (UiValidationError validationError : validationErrors)
                    message.append(validationError);
                focus(labelView);
                labelView.setError(message);
            }
        });
    }

    protected TextView errorMessageContainerView() {
        return (TextView) ((ViewGroup) toInputView().getParent().getParent()).findViewById(R.id.node_label); // TODO: Ugly!!!
    }

    protected void resetValidationErrors() {

    }

    protected void initOptions() {
        codeByViewId.clear();
        layout.removeAllViews();
        executor.execute(new LoadCodesTask());
    }

    protected void resetSelection() {
        attributesByCode.clear();
    }

    private EditText createQualifierInput() {
        final EditText editText = new AppCompatEditText(context);
        editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus)
                    saveQualifier();
            }
        });
        editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT)
                    saveQualifier();
                return false;
            }
        });
        editText.setText(qualifier(codeList.getQualifiableCode()));
        editText.setSingleLine();
        return editText;
    }

    private void saveQualifier() {
        if (codeList == null)
            return;
        UiCode code = codeList.getQualifiableCode();
        if (code == null)
            return;
        UiCodeAttribute attribute = attributesByCode.get(code);
        String newQualifier = qualifierInput.getText().toString().trim();
        if (attribute != null && ObjectUtils.notEqual(newQualifier, attribute.getQualifier())) {
            attribute.setQualifier(newQualifier);
            surveyService.updateAttribute(attribute);
        }
    }

    private void showQualifier() {
        qualified.set(true);
        uiHandler.post(new Runnable() {
            public void run() {
                if (layout.getChildCount() == codeList.getCodes().size()) {
                    layout.addView(qualifierInput);
                    showKeyboard(qualifierInput);
                }
            }
        });
    }<commit_msg>Prevent NPE modifying qualifiable multiple code attribute<commit_after>package org.openforis.collect.android.gui.input;

import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatEditText;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.*;
import org.apache.commons.lang3.ObjectUtils;
import org.openforis.collect.R;
import org.openforis.collect.android.CodeListService;
import org.openforis.collect.android.SurveyService;
import org.openforis.collect.android.gui.util.Keyboard;
import org.openforis.collect.android.viewmodel.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author <NAME>
 */
class CheckboxCodeAttributeCollectionComponent extends CodeAttributeCollectionComponent {
    private final SparseArray<UiCode> codeByViewId = new SparseArray<UiCode>();
    private final Map<UiCode, UiCodeAttribute> attributesByCode = new HashMap<UiCode, UiCodeAttribute>();
    private final LinearLayout layout;
    private EditText qualifierInput;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private AtomicBoolean qualified = new AtomicBoolean();

    CheckboxCodeAttributeCollectionComponent(UiAttributeCollection attributeCollection, CodeListService codeListService, SurveyService surveyService, FragmentActivity context) {
        super(attributeCollection, codeListService, surveyService, context);
        layout = new LinearLayout(context);
        layout.setOrientation(LinearLayout.VERTICAL);
        for (UiNode uiNode : attributeCollection.getChildren()) {
            UiCodeAttribute attribute = (UiCodeAttribute) uiNode;
            attributesByCode.put(attribute.getCode(), attribute);
        }
        initOptions();
    }

    public void saveNode() {
        super.saveNode();
        saveQualifier();
    }

    protected Set<UiAttribute> updateChangedAttributes() {
        return new HashSet<UiAttribute>();
    }

    protected View toInputView() {
        return layout;
    }

    public View getDefaultFocusedView() {
        return qualified.get() ? qualifierInput : null;
    }

    // TODO: Dry - same as in AttributeComponent
    protected void setValidationError(UiAttribute attribute, final Set<UiValidationError> validationErrors) {
        uiHandler.post(new Runnable() {
            public void run() {
                if (!isSelected())
                    return;
                TextView labelView = errorMessageContainerView();
                if (validationErrors == null || validationErrors.isEmpty()) {
                    labelView.setError(null);
                    return;
                }
                StringBuilder message = new StringBuilder();
                for (UiValidationError validationError : validationErrors)
                    message.append(validationError);
                focus(labelView);
                labelView.setError(message);
            }
        });
    }

    protected TextView errorMessageContainerView() {
        return (TextView) ((ViewGroup) toInputView().getParent().getParent()).findViewById(R.id.node_label); // TODO: Ugly!!!
    }

    protected void resetValidationErrors() {

    }

    protected void initOptions() {
        codeByViewId.clear();
        layout.removeAllViews();
        executor.execute(new LoadCodesTask());
    }

    protected void resetSelection() {
        attributesByCode.clear();
    }

    private EditText createQualifierInput() {
        final EditText editText = new AppCompatEditText(context);
        editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus)
                    saveQualifier();
            }
        });
        editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT)
                    saveQualifier();
                return false;
            }
        });
        editText.setText(qualifier(codeList.getQualifiableCode()));
        editText.setSingleLine();
        return editText;
    }

    private void saveQualifier() {
        if (codeList == null || qualifierInput == null)
            return;
        UiCode code = codeList.getQualifiableCode();
        if (code == null)
            return;
        UiCodeAttribute attribute = attributesByCode.get(code);
        String newQualifier = qualifierInput.getText().toString().trim();
        if (attribute != null && ObjectUtils.notEqual(newQualifier, attribute.getQualifier())) {
            attribute.setQualifier(newQualifier);
            surveyService.updateAttribute(attribute);
        }
    }

    private void showQualifier() {
        qualified.set(true);
        uiHandler.post(new Runnable() {
            public void run() {
                if (layout.getChildCount() == codeList.getCodes().size()) {
                    layout.addView(qualifierInput);
                    showKeyboard(qualifierInput);
                }
            }
        });
    }
{'fraction_non_alphanumeric': 0.0950563431479462, 'fraction_numerical': 0.0007270083605961468, 'mean_word_length': 2.74702076949268, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '539999', 'n_tokens_mistral': 2783, 'n_tokens_neox': 2714, 'n_words': 566}