KindSectionView.java revision 1b22073590c1801c3e6c7bde2f4636632a049f6c
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; 271b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Email; 281b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Event; 291b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Im; 301b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Note; 311b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Phone; 321b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Relation; 331b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 341b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 351b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Website; 36aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.provider.ContactsContract.Data; 373e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmannimport android.text.TextUtils; 38aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.util.AttributeSet; 3963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuanimport android.view.LayoutInflater; 40aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.view.View; 41aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.view.ViewGroup; 42aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkeyimport android.widget.LinearLayout; 431b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport android.widget.TextView; 44aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 4562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikovimport java.util.ArrayList; 461b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport java.util.HashMap; 471b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuanimport java.util.List; 4862bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov 49aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey/** 50aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Custom view for an entire section of data as segmented by 51aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a 52aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * section header and a trigger for adding new {@link Data} rows. 53aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey */ 54bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmannpublic class KindSectionView extends LinearLayout implements EditorListener { 55aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey private static final String TAG = "KindSectionView"; 56aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 57aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey private ViewGroup mEditors; 581b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private View mAddFieldFooter; 591b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private TextView mAddFieldText; 60f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann private String mTitleString; 61aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 62aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey private DataKind mKind; 63aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey private EntityDelta mState; 6492525ff51e2cb06531447a7dcde5e22334669c8eMegha Joshi private boolean mReadOnly; 656f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey 664b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki private ViewIdGenerator mViewIdGenerator; 674b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki 6863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan private LayoutInflater mInflater; 6991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov 701b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan /** 711b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * Map of data MIME types to the "add field" footer text resource ID 721b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * (that for example, maps to "Add new phone number"). 731b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan */ 741b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private static final HashMap<String, Integer> sAddFieldFooterTextResourceIds = 751b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan new HashMap<String, Integer>(); 761b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 771b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan static { 781b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan final HashMap<String, Integer> hashMap = sAddFieldFooterTextResourceIds; 791b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Phone.CONTENT_ITEM_TYPE, R.string.add_phone); 801b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Email.CONTENT_ITEM_TYPE, R.string.add_email); 811b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Im.CONTENT_ITEM_TYPE, R.string.add_im); 821b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(StructuredPostal.CONTENT_ITEM_TYPE, R.string.add_address); 831b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Note.CONTENT_ITEM_TYPE, R.string.add_note); 841b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Website.CONTENT_ITEM_TYPE, R.string.add_website); 851b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(SipAddress.CONTENT_ITEM_TYPE, R.string.add_internet_call); 861b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Event.CONTENT_ITEM_TYPE, R.string.add_event); 871b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan hashMap.put(Relation.CONTENT_ITEM_TYPE, R.string.add_relationship); 881b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 891b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 901b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan /** 911b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * List of the empty editor views. 921b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan */ 931b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private List<View> mEmptyEditorViews = new ArrayList<View>(); 941b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 95aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey public KindSectionView(Context context) { 9691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov this(context, null); 97aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 98aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 99aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey public KindSectionView(Context context, AttributeSet attrs) { 100aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey super(context, attrs); 101aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 102aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 10302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov @Override 10402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov public void setEnabled(boolean enabled) { 10502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov super.setEnabled(enabled); 10602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov if (mEditors != null) { 10702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov int childCount = mEditors.getChildCount(); 10802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov for (int i = 0; i < childCount; i++) { 10902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov mEditors.getChildAt(i).setEnabled(enabled); 11002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 11102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 11202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 1131b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (enabled && !mReadOnly) { 1141b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.VISIBLE); 1151b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } else { 1161b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.GONE); 11791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov } 11891d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov } 11991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov 12002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov public boolean isReadOnly() { 12102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov return mReadOnly; 12202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 12302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 124aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey /** {@inheritDoc} */ 125aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey @Override 126aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey protected void onFinishInflate() { 127aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey setDrawingCacheEnabled(true); 128aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey setAlwaysDrawnWithCacheEnabled(true); 129aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 13063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 13163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan 132aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey mEditors = (ViewGroup)findViewById(R.id.kind_editors); 1331b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldText = (TextView) findViewById(R.id.add_text); 1341b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter = findViewById(R.id.add_field_footer); 1351b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setOnClickListener(new OnClickListener() { 13679c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann @Override 137bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann public void onClick(View v) { 1381b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // Setup click listener to add an empty field when the footer is clicked. 1391b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.GONE); 1401b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan addItem(); 141bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann } 142bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann }); 143aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 144aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 1456f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey /** {@inheritDoc} */ 14679c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann @Override 147aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey public void onDeleted(Editor editor) { 1481b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateAddFooterVisible(); 1491b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateSectionVisible(); 150aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 151aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 1526f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey /** {@inheritDoc} */ 15379c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmann @Override 1546f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey public void onRequest(int request) { 1551b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // If a field has changed, then check if another row can be added dynamically. 1561b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (request == FIELD_CHANGED) { 1571b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateAddFooterVisible(); 1581b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 1596f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey } 1606f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey 1614b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) { 162aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey mKind = kind; 163aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey mState = state; 16492525ff51e2cb06531447a7dcde5e22334669c8eMegha Joshi mReadOnly = readOnly; 1654b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki mViewIdGenerator = vig; 1664b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki 1674b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki setId(mViewIdGenerator.getId(state, kind, null, ViewIdGenerator.NO_VIEW_INDEX)); 168aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 169aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey // TODO: handle resources from remote packages 170f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann mTitleString = (kind.titleRes == -1 || kind.titleRes == 0) 171f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann ? "" 172cfb525b3f18d71d6cc5d4ef36d704b3ba9e9a6f3Daniel Lehmann : getResources().getString(kind.titleRes); 173aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 1741b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // Set "add field" footer message according to MIME type. Some MIME types 1751b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // can only have max 1 field, so the map will return null if these sections 1761b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // should not have an "Add field" option. 1771b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan Integer textResourceId = sAddFieldFooterTextResourceIds.get(kind.mimeType); 1781b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (textResourceId != null) { 1791b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldText.setText(textResourceId); 1801b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 1811b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 182bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann rebuildFromState(); 1831b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateAddFooterVisible(); 1841b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateSectionVisible(); 185bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann } 186bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann 187f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann public String getTitle() { 188f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann return mTitleString; 189aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 190aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 191aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey /** 192aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey * Build editors for all current {@link #mState} rows. 193aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey */ 194aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey public void rebuildFromState() { 195aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey // Remove any existing editors 196aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey mEditors.removeAllViews(); 197aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 198da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann // Check if we are displaying anything here 199da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann boolean hasEntries = mState.hasMimeEntries(mKind.mimeType); 200da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann 201da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann if (hasEntries) { 202da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) { 203da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann // Skip entries that aren't visible 204da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann if (!entry.isVisible()) continue; 2053e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann if (isEmptyNoop(entry)) continue; 206da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann 207634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann createEditorView(entry); 208da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann } 209aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 210aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 211aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey 212634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann 213634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann /** 214634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann * Creates an EditorView for the given entry. This function must be used while constructing 215634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann * the views corresponding to the the object-model. The resulting EditorView is also added 216634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann * to the end of mEditors 217634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann */ 218634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann private View createEditorView(ValuesDelta entry) { 219634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann final View view; 22063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan try { 22163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false); 22263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan } catch (Exception e) { 22363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan throw new RuntimeException( 22463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan "Cannot allocate editor with layout resource ID " + 22563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan mKind.editorLayoutResourceId); 226634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann } 227634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann 22802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov view.setEnabled(isEnabled()); 22902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 230634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann if (view instanceof Editor) { 231634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann Editor editor = (Editor) view; 232634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator); 233634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann editor.setEditorListener(this); 234634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann editor.setDeletable(true); 235634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann } 236634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann mEditors.addView(view); 237634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann return view; 238634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann } 239634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann 2409e83c84a7603eb6fca1b42631d894731d61f7a34Daniel Lehmann /** 2413e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann * Tests whether the given item has no changes (so it exists in the database) but is empty 2423e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann */ 2433e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann private boolean isEmptyNoop(ValuesDelta item) { 2443e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann if (!item.isNoop()) return false; 2453e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann final int fieldCount = mKind.fieldList.size(); 2463e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann for (int i = 0; i < fieldCount; i++) { 2473e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann final String column = mKind.fieldList.get(i).column; 2483e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann final String value = item.getAsString(column); 2493e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann if (!TextUtils.isEmpty(value)) return false; 2503e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann } 2513e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann return true; 2523e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann } 2533e7436450f0fdd5ad939c3b46e7176e082c9ee11Daniel Lehmann 2541b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private void updateSectionVisible() { 255bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann setVisibility(getEditorCount() != 0 ? VISIBLE : GONE); 256bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann } 257bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann 2581b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan protected void updateAddFooterVisible() { 2591b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (!mReadOnly && mKind.isList) { 2601b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // First determine whether there are any existing empty editors. 2611b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateEmptyEditors(); 2621b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // If there are no existing empty editors and it's possible to add 2631b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // another field, then make the "add footer" field visible. 2641b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (!hasEmptyEditor() && EntityModifier.canInsert(mState, mKind)) { 2651b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.VISIBLE); 2661b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan return; 2671b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2681b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2691b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.GONE); 2701b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 271bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann 2721b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan /** 2731b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * Determines a list of {@link Editor} {@link View}s that have an empty 2741b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * field in them and removes extra ones, so there is max 1 empty 2751b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * {@link Editor} {@link View} at a time. 2761b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan */ 2771b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private void updateEmptyEditors() { 2781b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mEmptyEditorViews.clear(); 2791b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 2801b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // Construct a list of editors that have an empty field in them. 2811b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan for (int i = 0; i < mEditors.getChildCount(); i++) { 2821b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan View v = mEditors.getChildAt(i); 2831b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (((Editor) v).hasEmptyField()) { 2841b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mEmptyEditorViews.add(v); 2851b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2861b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2871b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 2881b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // If there is more than 1 empty editor, then remove it from the list of editors. 2891b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (mEmptyEditorViews.size() > 1) { 2901b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan for (View emptyEditorView : mEmptyEditorViews) { 2911b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // If no child {@link View}s are being focused on within 2921b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // this {@link View}, then remove this empty editor. 2931b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan if (emptyEditorView.findFocus() == null) { 2941b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mEditors.removeView(emptyEditorView); 2951b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2961b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2973f26e24c0cbc988b32d274b7a4e88c994355ef4fDaniel Lehmann } 2981b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan } 2991b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan 3001b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan /** 3011b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * Returns true if one of the editors has an empty field, or false 3021b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan * otherwise. 3031b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan */ 3041b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan private boolean hasEmptyEditor() { 3051b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan return mEmptyEditorViews.size() > 0; 306aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 3076f8d46b5fb96c2bead1317aae93a73fc89b093abJeff Sharkey 308bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann public void addItem() { 30962bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov ValuesDelta values = null; 310bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann // if this is a list, we can freely add. if not, only allow adding the first 31162bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov if (!mKind.isList) { 31262bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov if (getEditorCount() == 1) { 31362bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov return; 31462bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov } 31562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov 31662bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov // If we already have an item, just make it visible 31762bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov ArrayList<ValuesDelta> entries = mState.getMimeEntries(mKind.mimeType); 31862bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov if (entries != null && entries.size() > 0) { 31962bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov values = entries.get(0); 32062bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov } 32162bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov } 322da5fd9039bd303f5e4634a31ed9a00d58d679b39Daniel Lehmann 323634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann // Insert a new child, create its view and set its focus 32462bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov if (values == null) { 32562bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov values = EntityModifier.insertChild(mState, mKind); 32662bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov } 32762bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov 32862bab31374dd66462643cbc04ebb2acece4b9b39Dmitri Plotnikov final View newField = createEditorView(values); 329eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov post(new Runnable() { 330eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov 331eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov @Override 332eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov public void run() { 333eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov newField.requestFocus(); 334eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov } 335eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov }); 3364b722a93f1ecdeb2890fb7e5db4c22794bccfdcdMakoto Onuki 3371b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan // Hide the "add field" footer because there is now a blank field. 3381b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan mAddFieldFooter.setVisibility(View.GONE); 339eeac4dc8dccb20466669525f16dc58fa593a3483Daniel Lehmann 340634ab3baaf2bc69bd7977153fcdebf0e737e207dDaniel Lehmann // Ensure we are visible 3411b22073590c1801c3e6c7bde2f4636632a049f6cKatherine Kuan updateSectionVisible(); 342bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann } 343bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann 344bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann public int getEditorCount() { 345bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann return mEditors.getChildCount(); 346bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann } 347bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann 348bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann public DataKind getKind() { 349bb556954e29ae0700b729f128d8cd09ecdd91ee3Daniel Lehmann return mKind; 350aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey } 351aad8848282f51d73ad308e9ad3ebcef592fa153fJeff Sharkey} 352