LabeledEditorView.java revision 60b239c24c05233bbf3f7cb45697252e15ec76cc
1392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/*
2392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
4392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * you may not use this file except in compliance with the License.
6392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * You may obtain a copy of the License at
7392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
8392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
10392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * See the License for the specific language governing permissions and
14392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * limitations under the License.
15392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
16392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
19392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.ContactsUtils;
20392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.R;
214597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType.DataKind;
224597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType.EditType;
23392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.model.EntityDelta;
24392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.model.EntityDelta.ValuesDelta;
25392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.model.EntityModifier;
26392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.util.DialogManager;
27392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport com.android.contacts.util.DialogManager.DialogShowingView;
282fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport com.android.contacts.util.ThemeUtils;
29392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
30392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.app.AlertDialog;
31392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.app.Dialog;
32392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.Context;
33392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.DialogInterface;
34392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.Entity;
35392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.res.Resources;
36392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.Bundle;
3779c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmannimport android.os.Handler;
3811bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikovimport android.text.TextUtils;
39392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.util.AttributeSet;
402fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.view.LayoutInflater;
41392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.View;
42392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.ViewGroup;
43392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.inputmethod.EditorInfo;
442fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.AdapterView;
452fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.AdapterView.OnItemSelectedListener;
462fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.ArrayAdapter;
47392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.widget.EditText;
48392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.widget.ImageButton;
492fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.Spinner;
502fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.TextView;
51392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
5214918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikovimport java.util.List;
5314918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov
54392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/**
55392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Base class for editors that handles labels and values.
56392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Uses {@link ValuesDelta} to read any existing
57392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * {@link Entity} values, and to correctly write any changes values.
58392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
59392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannpublic abstract class LabeledEditorView extends ViewGroup implements Editor, DialogShowingView {
60392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected static final String DIALOG_ID_KEY = "dialog_id";
61392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int DIALOG_ID_CUSTOM = 1;
62392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
63392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int INPUT_TYPE_CUSTOM = EditorInfo.TYPE_CLASS_TEXT
64392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
65392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
662fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private Spinner mLabel;
672fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private EditTypeAdapter mEditTypeAdapter;
68392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private ImageButton mDelete;
69392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
70392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DataKind mKind;
71392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private ValuesDelta mEntry;
72392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EntityDelta mState;
73392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private boolean mReadOnly;
74392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
75392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EditType mType;
76392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
77392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
78392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DialogManager mDialogManager = null;
79392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EditorListener mListener;
8091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected int mMinLineItemHeight;
81392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
822fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    /**
832fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov     * A marker in the spinner adapter of the currently selected custom type.
842fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov     */
852fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    public static final EditType CUSTOM_SELECTION = new EditType(0, 0);
862fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
872fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private OnItemSelectedListener mSpinnerListener = new OnItemSelectedListener() {
882fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
892fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
902fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public void onItemSelected(
912fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                AdapterView<?> parent, View view, int position, long id) {
922fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            onTypeSelectionChange(position);
932fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
942fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
952fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
962fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public void onNothingSelected(AdapterView<?> parent) {
972fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
982fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    };
992fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
100392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context) {
101392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context);
10291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
103392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
104392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
105392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context, AttributeSet attrs) {
106392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs);
10791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
108392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
109392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
110392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context, AttributeSet attrs, int defStyle) {
111392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs, defStyle);
11291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
11391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
11491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
11591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    private void init(Context context) {
11691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        mMinLineItemHeight = context.getResources().getDimensionPixelSize(
11791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                R.dimen.editor_min_line_item_height);
118392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
119392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
12002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public boolean isReadOnly() {
12102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        return mReadOnly;
12202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
12302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
12491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    public int getBaseline(int row) {
12591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        if (row == 0 && mLabel != null) {
12691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            return mLabel.getBaseline();
12791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        }
12891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        return -1;
12991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
13091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
13191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    /**
13291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov     * Returns the number of rows in this editor, including the invisible ones.
13391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov     */
13491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected int getLineItemCount() {
13591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        return 1;
13691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
13791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
13891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected boolean isLineItemVisible(int row) {
13991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        return true;
14091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
14191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
14291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected int getLineItemHeight(int row) {
14391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        int fieldHeight = 0;
14491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        int buttonHeight = 0;
14591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        if (row == 0) {
14691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            // summarize the EditText heights
14791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            if (mLabel != null) {
14891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                fieldHeight = mLabel.getMeasuredHeight();
14991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            }
15091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
15191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            // Ensure there is enough space for the minus button
15291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            View deleteButton = getDelete();
15391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            final int deleteHeight = (deleteButton != null) ? deleteButton.getMeasuredHeight() : 0;
15491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            buttonHeight += deleteHeight;
15591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        }
15691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
15791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        return Math.max(Math.max(buttonHeight, fieldHeight), mMinLineItemHeight);
15891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
15991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
16091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    @Override
16191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
16291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        measureChildren(widthMeasureSpec, heightMeasureSpec);
16391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
16491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        int height = 0;
16591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        height += getPaddingTop() + getPaddingBottom();
16691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
16791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        int count = getLineItemCount();
16891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        for (int i = 0; i < count; i++) {
16991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            if (isLineItemVisible(i)) {
17091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                height += getLineItemHeight(i);
17191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            }
17291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        }
17391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
17491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
17591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                resolveSize(height, heightMeasureSpec));
17691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
17791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
178392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
179392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onLayout(boolean changed, int l, int t, int r, int b) {
180392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Subtract padding from the borders ==> x1 variables
181392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int t1 = getPaddingTop();
182392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int r1 = getMeasuredWidth() - getPaddingRight();
183392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int b1 = getMeasuredHeight() - getPaddingBottom();
184392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
185cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        final int r2;
186cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        if (mDelete != null) {
187cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann            r2 = r1 - mDelete.getMeasuredWidth();
18891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            // Vertically center the delete button in the first line item
18991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            int height = mDelete.getMeasuredHeight();
19091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            int top = t1 + (mMinLineItemHeight - height) / 2;
191cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann            mDelete.layout(
19291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                    r2, top,
19391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                    r1, top + height);
194cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        } else {
195cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann            r2 = r1;
196cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        }
197392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
198cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann        if (mLabel != null) {
19991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            int baseline = getBaseline(0);
20091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            int y = t1 + baseline - mLabel.getBaseline();
201392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mLabel.layout(
20291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                    r2 - mLabel.getMeasuredWidth(), y,
20391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                    r2, y + mLabel.getMeasuredHeight());
204392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
205392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
206392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
207392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
208392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Creates or removes the type/label button. Doesn't do anything if already correctly configured
209392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
210392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void setupLabelButton(boolean shouldExist) {
211392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (shouldExist && mLabel == null) {
2122fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel = new Spinner(mContext);
213392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final int width =
214392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mContext.getResources().getDimensionPixelSize(R.dimen.editor_type_label_width);
215392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mLabel.setLayoutParams(new LayoutParams(width, LayoutParams.WRAP_CONTENT));
2162fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel.setOnItemSelectedListener(mSpinnerListener);
21702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mLabel.setEnabled(!mReadOnly && isEnabled());
218392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            addView(mLabel);
219392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        } else if (!shouldExist && mLabel != null) {
220392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            removeView(mLabel);
221392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mLabel = null;
222392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
223392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
224392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
225392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
226392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Creates or removes the remove button. Doesn't do anything if already correctly configured
227392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
228392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void setupDeleteButton(boolean shouldExist) {
229392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (shouldExist && mDelete == null) {
230392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete = new ImageButton(mContext);
231915ffc5ae1d10a7ed06d5541fe81da023fa3228fDaniel Lehmann            mDelete.setImageResource(R.drawable.ic_menu_remove_field_holo_light);
23279c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann            mDelete.setBackgroundResource(
23379c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                    ThemeUtils.getSelectableItemBackground(mContext.getTheme()));
234392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            final Resources resources = mContext.getResources();
235392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete.setPadding(
236392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_left),
237392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_top),
238392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_right),
239392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    resources.getDimensionPixelOffset(R.dimen.editor_round_button_padding_bottom));
240392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete.setContentDescription(
241392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    getResources().getText(R.string.description_minus_button));
242392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete.setLayoutParams(
243392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
244392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete.setOnClickListener(new OnClickListener() {
245392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                @Override
246392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                public void onClick(View v) {
24779c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                    // defer removal of this button so that the pressed state is visible shortly
24879c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                    new Handler().post(new Runnable() {
24979c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                        @Override
25079c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                        public void run() {
25179c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                            // Keep around in model, but mark as deleted
25279c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                            mEntry.markDeleted();
25379c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann
25479c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                            ((ViewGroup) getParent()).removeView(LabeledEditorView.this);
25579c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann
25679c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                            if (mListener != null) {
25779c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                                // Notify listener when present
25879c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                                mListener.onDeleted(LabeledEditorView.this);
25979c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                            }
26079c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                        }
26179c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann                    });
262392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
263392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            });
26402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mDelete.setEnabled(!mReadOnly && isEnabled());
265392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            addView(mDelete);
266392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        } else if (!shouldExist && mDelete != null) {
267392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            removeView(mDelete);
268392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDelete = null;
269392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
270392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
271392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
272392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onOptionalFieldVisibilityChange() {
273392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mListener != null) {
274392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mListener.onRequest(EditorListener.EDITOR_FORM_CHANGED);
275392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
276392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
277392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
278392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
279392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setEditorListener(EditorListener listener) {
280392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mListener = listener;
281392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
282392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
283392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
284392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setDeletable(boolean deletable) {
285392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setupDeleteButton(deletable);
286392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
287392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
288392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
289392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setEnabled(boolean enabled) {
29002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        super.setEnabled(enabled);
29102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mLabel != null) mLabel.setEnabled(!mReadOnly && enabled);
29202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mDelete != null) mDelete.setEnabled(!mReadOnly && enabled);
293392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
294392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
2952fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    public Spinner getLabel() {
296392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mLabel;
297392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
298392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
299392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public ImageButton getDelete() {
300392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mDelete;
301392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
302392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
303392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected DataKind getKind() {
304392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mKind;
305392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
306392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
307392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected ValuesDelta getEntry() {
308392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mEntry;
309392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
310392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
311392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected EditType getType() {
312392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mType;
313392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
314392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
315392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
316392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Build the current label state based on selected {@link EditType} and
317392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * possible custom label string.
318392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
319392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void rebuildLabel() {
320392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mLabel == null) return;
3212fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        mEditTypeAdapter = new EditTypeAdapter(mContext);
3222fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        mLabel.setAdapter(mEditTypeAdapter);
3232fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mEditTypeAdapter.hasCustomSelection()) {
3242fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel.setSelection(mEditTypeAdapter.getPosition(CUSTOM_SELECTION));
3252fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        } else {
3262fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel.setSelection(mEditTypeAdapter.getPosition(mType));
327392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
328392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
329392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
330392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
331392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void onFieldChanged(String column, String value) {
33211bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov        if (!isFieldChanged(column, value)) {
3337d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov            return;
3347d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov        }
3357d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov
336392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Field changes are saved directly
337392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mEntry.put(column, value);
338392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mListener != null) {
339392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mListener.onRequest(EditorListener.FIELD_CHANGED);
340392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
341392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
342392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
34311bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov    protected boolean isFieldChanged(String column, String value) {
34460b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String dbValue = mEntry.getAsString(column);
34560b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        // nullable fields (e.g. Middle Name) are usually represented as empty columns,
34660b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        // so lets treat null and empty space equivalently here
34760b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String dbValueNoNull = dbValue == null ? "" : dbValue;
34860b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String valueNoNull = value == null ? "" : value;
34960b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        return !TextUtils.equals(dbValueNoNull, valueNoNull);
35011bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov    }
35111bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov
352392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void rebuildValues() {
353392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setValues(mKind, mEntry, mState, mReadOnly, mViewIdGenerator);
354392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
355392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
356392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
357392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Prepare this editor using the given {@link DataKind} for defining
358392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * structure and {@link ValuesDelta} describing the content to edit.
359392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
360392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
361392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
362392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            ViewIdGenerator vig) {
363392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mKind = kind;
364392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mEntry = entry;
365392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mState = state;
366392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mReadOnly = readOnly;
367392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mViewIdGenerator = vig;
368392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setId(vig.getId(state, kind, entry, ViewIdGenerator.NO_VIEW_INDEX));
369392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
370392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (!entry.isVisible()) {
371392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            // Hide ourselves entirely if deleted
372392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            setVisibility(View.GONE);
373392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            return;
374392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
375392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setVisibility(View.VISIBLE);
376392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
377392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Display label selector if multiple types available
378392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        final boolean hasTypes = EntityModifier.hasEditTypes(kind);
379392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setupLabelButton(hasTypes);
38002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mLabel != null) mLabel.setEnabled(!readOnly && isEnabled());
381392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (hasTypes) {
382392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mType = EntityModifier.getCurrentType(entry, kind);
383392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            rebuildLabel();
384392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
385392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
386392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
387392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public ValuesDelta getValues() {
388392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mEntry;
389392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
390392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
391392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
392392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Prepare dialog for entering a custom label. The input value is trimmed: white spaces before
393392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * and after the input text is removed.
394392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * <p>
395392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * If the final value is empty, this change request is ignored;
396392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * no empty text is allowed in any custom label.
397392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
398392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private Dialog createCustomDialog() {
399392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        final EditText customType = new EditText(mContext);
400cb08f1b2a3f2e6e21aa5d993cf44d04658316cccDmitri Plotnikov        customType.setId(R.id.custom_dialog_content);
401392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        customType.setInputType(INPUT_TYPE_CUSTOM);
40214918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov        customType.setSaveEnabled(true);
403392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        customType.requestFocus();
404392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
405392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
406392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setTitle(R.string.customLabelPickerTitle);
407392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setView(customType);
408392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
409392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
410392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            @Override
411392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            public void onClick(DialogInterface dialog, int which) {
412392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                final String customText = customType.getText().toString().trim();
413392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                if (ContactsUtils.isGraphic(customText)) {
41414918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    final List<EditType> allTypes =
41514918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                            EntityModifier.getValidTypes(mState, mKind, null);
41614918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    mType = null;
41714918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    for (EditType editType : allTypes) {
41814918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                        if (editType.customColumn != null) {
41914918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                            mType = editType;
42014918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                            break;
42114918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                        }
42214918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    }
42314918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    if (mType == null) return;
42414918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov
425392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mEntry.put(mKind.typeColumn, mType.rawValue);
426392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mEntry.put(mType.customColumn, customText);
427392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    rebuildLabel();
428392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    requestFocusForFirstEditField();
429392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    onLabelRebuilt();
430392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
431392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
432392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        });
433392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
434392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setNegativeButton(android.R.string.cancel, null);
435392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
436392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return builder.create();
437392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
438392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
439392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
440392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Called after the label has changed (either chosen from the list or entered in the Dialog)
441392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
442392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onLabelRebuilt() {
443392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
444392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4452fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    protected void onTypeSelectionChange(int position) {
4462fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        EditType selected = mEditTypeAdapter.getItem(position);
4472fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        // See if the selection has in fact changed
4482fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mEditTypeAdapter.hasCustomSelection() && selected == CUSTOM_SELECTION) {
4492fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return;
450392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
451392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4522fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mType == selected && mType.customColumn == null) {
4532fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return;
4542fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
455392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4562fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (selected.customColumn != null) {
4572fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            showDialog(DIALOG_ID_CUSTOM);
4582fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        } else {
4592fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            // User picked type, and we're sure it's ok to actually write the entry.
4602fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mType = selected;
4612fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mEntry.put(mKind.typeColumn, mType.rawValue);
4622fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            rebuildLabel();
4632fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            requestFocusForFirstEditField();
4642fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            onLabelRebuilt();
4652fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
466392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
467392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
468392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /* package */
469392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    void showDialog(int bundleDialogId) {
470392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        Bundle bundle = new Bundle();
471392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        bundle.putInt(DIALOG_ID_KEY, bundleDialogId);
472392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        getDialogManager().showDialogInView(this, bundle);
473392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
474392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
475392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DialogManager getDialogManager() {
476392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mDialogManager == null) {
477392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            Context context = getContext();
478392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (!(context instanceof DialogManager.DialogShowingViewActivity)) {
479392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                throw new IllegalStateException(
480392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        "View must be hosted in an Activity that implements " +
481392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        "DialogManager.DialogShowingViewActivity");
482392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
483392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDialogManager = ((DialogManager.DialogShowingViewActivity)context).getDialogManager();
484392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
485392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mDialogManager;
486392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
487392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
488392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
489392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public Dialog createDialog(Bundle bundle) {
490392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (bundle == null) throw new IllegalArgumentException("bundle must not be null");
491392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int dialogId = bundle.getInt(DIALOG_ID_KEY);
492392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        switch (dialogId) {
493392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            case DIALOG_ID_CUSTOM:
494392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                return createCustomDialog();
495392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            default:
496392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                throw new IllegalArgumentException("Invalid dialogId: " + dialogId);
497392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
498392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
499392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
500392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected abstract void requestFocusForFirstEditField();
5012fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5022fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private class EditTypeAdapter extends ArrayAdapter<EditType> {
5032fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private final LayoutInflater mInflater;
5042fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private boolean mHasCustomSelection;
5052fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5062fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public EditTypeAdapter(Context context) {
5072fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            super(context, 0);
5082fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
5092fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5104fa9cd0088de76d83803210b39f373cd980fd846Dmitri Plotnikov            if (mType != null && mType.customColumn != null) {
5112fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5122fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                // Use custom label string when present
5132fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                final String customText = mEntry.getAsString(mType.customColumn);
5142fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                if (customText != null) {
5152fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    add(CUSTOM_SELECTION);
5162fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    mHasCustomSelection = true;
5172fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                }
5182fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
5192fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5202fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            addAll(EntityModifier.getValidTypes(mState, mKind, mType));
5212fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5222fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5232fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public boolean hasCustomSelection() {
5242fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return mHasCustomSelection;
5252fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5262fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5272fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
5282fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public View getView(int position, View convertView, ViewGroup parent) {
5292fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return createViewFromResource(
5302fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    position, convertView, parent, android.R.layout.simple_spinner_item);
5312fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5322fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5332fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
5342fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public View getDropDownView(int position, View convertView, ViewGroup parent) {
5352fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return createViewFromResource(
5362fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    position, convertView, parent, android.R.layout.simple_spinner_dropdown_item);
5372fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5382fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5392fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private View createViewFromResource(int position, View convertView, ViewGroup parent,
5402fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                int resource) {
5412fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            View view;
5422fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            TextView textView;
5432fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5442fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            if (convertView == null) {
5452fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                view = mInflater.inflate(resource, parent, false);
5462fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            } else {
5472fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                view = convertView;
5482fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
5492fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5502fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            textView = (TextView) view;
5512fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5522fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            EditType type = getItem(position);
5532fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            String text;
5542fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            if (type == CUSTOM_SELECTION) {
5552fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                text = mEntry.getAsString(mType.customColumn);
5562fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            } else {
5572fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                text = getContext().getString(type.labelRes);
5582fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
5592fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            textView.setText(text);
5602fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return view;
5612fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5622fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    }
563392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann}
564