1aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey/*
2aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Copyright (C) 2009 The Android Open Source Project
3aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey *
4aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * you may not use this file except in compliance with the License.
6aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * You may obtain a copy of the License at
7aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey *
8aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey *
10aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * See the License for the specific language governing permissions and
14aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * limitations under the License.
15aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey */
16aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
19aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport com.android.contacts.R;
2018ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.Editor.EditorListener;
21405671a7b42d97ebf7ae7c0eeb4721f881139673Daisuke Miyakawaimport com.android.contacts.model.DataKind;
22d25f958595b190586bd838d50718b1a2a3f0d417Dmitri Plotnikovimport com.android.contacts.model.EntityDelta;
23aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport com.android.contacts.model.EntityDelta.ValuesDelta;
24d25f958595b190586bd838d50718b1a2a3f0d417Dmitri Plotnikovimport com.android.contacts.model.EntityModifier;
25aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
26aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.content.Context;
273e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmannimport android.text.TextUtils;
28aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.util.AttributeSet;
2963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuanimport android.view.LayoutInflater;
30aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.view.View;
31aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.view.ViewGroup;
32aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.widget.LinearLayout;
331b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.widget.TextView;
34aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
3562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikovimport java.util.ArrayList;
361b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport java.util.List;
3762bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov
38aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey/**
39aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Custom view for an entire section of data as segmented by
40aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a
41aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * section header and a trigger for adding new {@link Data} rows.
42aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey */
43bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmannpublic class KindSectionView extends LinearLayout implements EditorListener {
44aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    private static final String TAG = "KindSectionView";
45aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
46a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan    private TextView mTitle;
47aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    private ViewGroup mEditors;
481b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    private View mAddFieldFooter;
49f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann    private String mTitleString;
50aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
51aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    private DataKind mKind;
52aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    private EntityDelta mState;
5392525ff51e2cb06531447a7dcde5e22334669c8eMegha Joshi    private boolean mReadOnly;
546f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey
554b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki    private ViewIdGenerator mViewIdGenerator;
564b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki
5763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    private LayoutInflater mInflater;
5891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
59aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    public KindSectionView(Context context) {
6091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        this(context, null);
61aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
62aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
63aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    public KindSectionView(Context context, AttributeSet attrs) {
64aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        super(context, attrs);
65aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
66aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
6702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    @Override
6802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
6902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        super.setEnabled(enabled);
7002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEditors != null) {
7102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            int childCount = mEditors.getChildCount();
7202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            for (int i = 0; i < childCount; i++) {
7302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                mEditors.getChildAt(i).setEnabled(enabled);
7402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
7502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
7602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
771b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        if (enabled && !mReadOnly) {
781b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            mAddFieldFooter.setVisibility(View.VISIBLE);
791b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        } else {
801b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            mAddFieldFooter.setVisibility(View.GONE);
8191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        }
8291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
8391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
8402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public boolean isReadOnly() {
8502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        return mReadOnly;
8602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
8702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
88aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    /** {@inheritDoc} */
89aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    @Override
90aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    protected void onFinishInflate() {
91aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        setDrawingCacheEnabled(true);
92aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        setAlwaysDrawnWithCacheEnabled(true);
93aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
9463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
9563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan
96a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        mTitle = (TextView) findViewById(R.id.kind_title);
97a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        mEditors = (ViewGroup) findViewById(R.id.kind_editors);
981b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        mAddFieldFooter = findViewById(R.id.add_field_footer);
991b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        mAddFieldFooter.setOnClickListener(new OnClickListener() {
10079c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann            @Override
101bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann            public void onClick(View v) {
1021b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                // Setup click listener to add an empty field when the footer is clicked.
1031b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                mAddFieldFooter.setVisibility(View.GONE);
1041b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                addItem();
105bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann            }
106bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann        });
107aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
108aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
10979c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann    @Override
1102293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    public void onDeleteRequested(Editor editor) {
1112293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // If there is only 1 editor in the section, then don't allow the user to delete it.
1122293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // Just clear the fields in the editor.
1132293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        if (getEditorCount() == 1) {
1142293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            editor.clearAllFields();
1152293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        } else {
1162293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            // Otherwise it's okay to delete this {@link Editor}
1172293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            editor.deleteEditor();
1182293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        }
1191b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        updateAddFooterVisible();
120aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
121aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
12279c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann    @Override
1236f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey    public void onRequest(int request) {
1242591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        // If a field has become empty or non-empty, then check if another row
1252591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        // can be added dynamically.
1262591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        if (request == FIELD_TURNED_EMPTY || request == FIELD_TURNED_NON_EMPTY) {
1271b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            updateAddFooterVisible();
1281b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        }
1296f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey    }
1306f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey
1314b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki    public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) {
132aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        mKind = kind;
133aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        mState = state;
13492525ff51e2cb06531447a7dcde5e22334669c8eMegha Joshi        mReadOnly = readOnly;
1354b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki        mViewIdGenerator = vig;
1364b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki
1374b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki        setId(mViewIdGenerator.getId(state, kind, null, ViewIdGenerator.NO_VIEW_INDEX));
138aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
139aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        // TODO: handle resources from remote packages
140f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann        mTitleString = (kind.titleRes == -1 || kind.titleRes == 0)
141f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann                ? ""
142cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann                : getResources().getString(kind.titleRes);
143fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan        mTitle.setText(mTitleString);
144aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
145bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann        rebuildFromState();
1461b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        updateAddFooterVisible();
1471b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        updateSectionVisible();
148bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    }
149bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann
150f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann    public String getTitle() {
151f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann        return mTitleString;
152aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
153aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
1543fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan    public void setTitleVisible(boolean visible) {
1553fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan        findViewById(R.id.kind_title_layout).setVisibility(visible ? View.VISIBLE : View.GONE);
1563fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan    }
1573fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan
158aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    /**
159aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey     * Build editors for all current {@link #mState} rows.
160aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey     */
161aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    public void rebuildFromState() {
162aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        // Remove any existing editors
163aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        mEditors.removeAllViews();
164aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
165da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann        // Check if we are displaying anything here
166da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann        boolean hasEntries = mState.hasMimeEntries(mKind.mimeType);
167da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann
168da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann        if (hasEntries) {
169da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann            for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
170da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann                // Skip entries that aren't visible
171da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann                if (!entry.isVisible()) continue;
1723e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann                if (isEmptyNoop(entry)) continue;
173da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann
174634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann                createEditorView(entry);
175da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann            }
176aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey        }
177aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
178aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey
179634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann
180634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann    /**
181634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann     * Creates an EditorView for the given entry. This function must be used while constructing
182634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann     * the views corresponding to the the object-model. The resulting EditorView is also added
183634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann     * to the end of mEditors
184634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann     */
185634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann    private View createEditorView(ValuesDelta entry) {
186634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        final View view;
18763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        try {
18863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false);
18963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        } catch (Exception e) {
19063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            throw new RuntimeException(
19163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    "Cannot allocate editor with layout resource ID " +
1922591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan                    mKind.editorLayoutResourceId + " for MIME type " + mKind.mimeType +
1932591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan                    " with error " + e.toString());
194634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        }
195634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann
19602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        view.setEnabled(isEnabled());
19702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
198634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        if (view instanceof Editor) {
199634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann            Editor editor = (Editor) view;
2005e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan            editor.setDeletable(true);
201634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann            editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
202634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann            editor.setEditorListener(this);
203634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        }
204634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        mEditors.addView(view);
205634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        return view;
206634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann    }
207634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann
2089e83c84a7603eb6fca1b42631d894731d61f7a34Daniel Lehmann    /**
2093e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann     * Tests whether the given item has no changes (so it exists in the database) but is empty
2103e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann     */
2113e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann    private boolean isEmptyNoop(ValuesDelta item) {
2123e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann        if (!item.isNoop()) return false;
2133e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann        final int fieldCount = mKind.fieldList.size();
2143e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann        for (int i = 0; i < fieldCount; i++) {
2153e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann            final String column = mKind.fieldList.get(i).column;
2163e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann            final String value = item.getAsString(column);
2173e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann            if (!TextUtils.isEmpty(value)) return false;
2183e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann        }
2193e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann        return true;
2203e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann    }
2213e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann
2221b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    private void updateSectionVisible() {
223bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann        setVisibility(getEditorCount() != 0 ? VISIBLE : GONE);
224bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    }
225bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann
2261b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    protected void updateAddFooterVisible() {
22750a27b70581b0191995969c63edd1f6a3db3d1b7Makoto Onuki        if (!mReadOnly && (mKind.typeOverallMax != 1)) {
2281b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            // First determine whether there are any existing empty editors.
2291b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            updateEmptyEditors();
2301b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            // If there are no existing empty editors and it's possible to add
2311b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            // another field, then make the "add footer" field visible.
2321b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            if (!hasEmptyEditor() && EntityModifier.canInsert(mState, mKind)) {
2331b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                mAddFieldFooter.setVisibility(View.VISIBLE);
2341b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                return;
2351b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            }
2361b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        }
2371b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        mAddFieldFooter.setVisibility(View.GONE);
2381b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    }
239bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann
2401b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    /**
2412591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * Updates the editors being displayed to the user removing extra empty
2422591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * {@link Editor}s, so there is only max 1 empty {@link Editor} view at a time.
2431b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     */
2441b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    private void updateEmptyEditors() {
2452591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        List<View> emptyEditors = getEmptyEditors();
2461b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan
2471b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        // If there is more than 1 empty editor, then remove it from the list of editors.
2482591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        if (emptyEditors.size() > 1) {
2492591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            for (View emptyEditorView : emptyEditors) {
2501b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                // If no child {@link View}s are being focused on within
2511b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                // this {@link View}, then remove this empty editor.
2521b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                if (emptyEditorView.findFocus() == null) {
2531b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                    mEditors.removeView(emptyEditorView);
2541b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan                }
2551b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan            }
2563f26e24c0cbc988b32d274b7a4e88c994355ef4fDaniel Lehmann        }
2571b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    }
2581b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan
2591b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    /**
2602591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * Returns a list of empty editor views in this section.
2612591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     */
2622591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    private List<View> getEmptyEditors() {
2632591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        List<View> emptyEditorViews = new ArrayList<View>();
2642591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        for (int i = 0; i < mEditors.getChildCount(); i++) {
2652591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            View view = mEditors.getChildAt(i);
2662591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            if (((Editor) view).isEmpty()) {
2672591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan                emptyEditorViews.add(view);
2682591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            }
2692591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        }
2702591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        return emptyEditorViews;
2712591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    }
2722591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan
2732591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    /**
2742591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan     * Returns true if one of the editors has all of its fields empty, or false
2751b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     * otherwise.
2761b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan     */
2771b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan    private boolean hasEmptyEditor() {
2782591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        return getEmptyEditors().size() > 0;
279aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
2806f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey
2813fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan    /**
2823fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan     * Returns true if all editors are empty.
2833fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan     */
2843fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan    public boolean isEmpty() {
2853fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan        for (int i = 0; i < mEditors.getChildCount(); i++) {
2863fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan            View view = mEditors.getChildAt(i);
2873fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan            if (!((Editor) view).isEmpty()) {
2883fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan                return false;
2893fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan            }
2903fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan        }
2913fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan        return true;
2923fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan    }
2933fa75acf99f5245eae00c77086ff130b3552ceecKatherine Kuan
294bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    public void addItem() {
29562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov        ValuesDelta values = null;
2962591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        // If this is a list, we can freely add. If not, only allow adding the first.
29750a27b70581b0191995969c63edd1f6a3db3d1b7Makoto Onuki        if (mKind.typeOverallMax == 1) {
29862bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            if (getEditorCount() == 1) {
29962bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov                return;
30062bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            }
30162bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov
30262bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            // If we already have an item, just make it visible
30362bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            ArrayList<ValuesDelta> entries = mState.getMimeEntries(mKind.mimeType);
30462bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            if (entries != null && entries.size() > 0) {
30562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov                values = entries.get(0);
30662bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            }
30762bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov        }
308da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann
309634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        // Insert a new child, create its view and set its focus
31062bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov        if (values == null) {
31162bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov            values = EntityModifier.insertChild(mState, mKind);
31262bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov        }
31362bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov
31462bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov        final View newField = createEditorView(values);
315eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        post(new Runnable() {
316eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
317eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov            @Override
318eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov            public void run() {
319eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov                newField.requestFocus();
320eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov            }
321eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        });
3224b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki
3231b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        // Hide the "add field" footer because there is now a blank field.
3241b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        mAddFieldFooter.setVisibility(View.GONE);
325eeac4dc8dccb20466669525f16dc58fa593a3483Daniel Lehmann
326634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann        // Ensure we are visible
3271b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan        updateSectionVisible();
328bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    }
329bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann
330bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    public int getEditorCount() {
331bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann        return mEditors.getChildCount();
332bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    }
333bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann
334bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann    public DataKind getKind() {
335bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann        return mKind;
336aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey    }
337aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey}
338