Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.contacts.ui.widget;
     18 
     19 import com.android.contacts.R;
     20 import com.android.contacts.model.Editor;
     21 import com.android.contacts.model.EntityDelta;
     22 import com.android.contacts.model.EntityModifier;
     23 import com.android.contacts.model.ContactsSource.DataKind;
     24 import com.android.contacts.model.Editor.EditorListener;
     25 import com.android.contacts.model.EntityDelta.ValuesDelta;
     26 import com.android.contacts.ui.ViewIdGenerator;
     27 
     28 import android.content.Context;
     29 import android.provider.ContactsContract.Data;
     30 import android.util.AttributeSet;
     31 import android.view.LayoutInflater;
     32 import android.view.View;
     33 import android.view.ViewGroup;
     34 import android.view.View.OnClickListener;
     35 import android.widget.ImageView;
     36 import android.widget.LinearLayout;
     37 import android.widget.TextView;
     38 
     39 /**
     40  * Custom view for an entire section of data as segmented by
     41  * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a
     42  * section header and a trigger for adding new {@link Data} rows.
     43  */
     44 public class KindSectionView extends LinearLayout implements OnClickListener, EditorListener {
     45     private static final String TAG = "KindSectionView";
     46 
     47     private LayoutInflater mInflater;
     48 
     49     private ViewGroup mEditors;
     50     private View mAdd;
     51     private ImageView mAddPlusButton;
     52     private TextView mTitle;
     53 
     54     private DataKind mKind;
     55     private EntityDelta mState;
     56     private boolean mReadOnly;
     57 
     58     private ViewIdGenerator mViewIdGenerator;
     59 
     60     public KindSectionView(Context context) {
     61         super(context);
     62     }
     63 
     64     public KindSectionView(Context context, AttributeSet attrs) {
     65         super(context, attrs);
     66     }
     67 
     68     /** {@inheritDoc} */
     69     @Override
     70     protected void onFinishInflate() {
     71         mInflater = (LayoutInflater)getContext().getSystemService(
     72                 Context.LAYOUT_INFLATER_SERVICE);
     73 
     74         setDrawingCacheEnabled(true);
     75         setAlwaysDrawnWithCacheEnabled(true);
     76 
     77         mEditors = (ViewGroup)findViewById(R.id.kind_editors);
     78 
     79         mAdd = findViewById(R.id.kind_header);
     80         mAdd.setOnClickListener(this);
     81 
     82         mAddPlusButton = (ImageView) findViewById(R.id.kind_plus);
     83 
     84         mTitle = (TextView)findViewById(R.id.kind_title);
     85     }
     86 
     87     /** {@inheritDoc} */
     88     public void onDeleted(Editor editor) {
     89         this.updateAddEnabled();
     90         this.updateEditorsVisible();
     91     }
     92 
     93     /** {@inheritDoc} */
     94     public void onRequest(int request) {
     95         // Ignore requests
     96     }
     97 
     98     public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) {
     99         mKind = kind;
    100         mState = state;
    101         mReadOnly = readOnly;
    102         mViewIdGenerator = vig;
    103 
    104         setId(mViewIdGenerator.getId(state, kind, null, ViewIdGenerator.NO_VIEW_INDEX));
    105 
    106         // TODO: handle resources from remote packages
    107         mTitle.setText(kind.titleRes);
    108 
    109         // Only show the add button if this is a list
    110         mAddPlusButton.setVisibility(mKind.isList ? View.VISIBLE : View.GONE);
    111 
    112         this.rebuildFromState();
    113         this.updateAddEnabled();
    114         this.updateEditorsVisible();
    115     }
    116 
    117     public boolean isAnyEditorFilledOut() {
    118         if (mState == null) {
    119             return false;
    120         }
    121 
    122         if (!mState.hasMimeEntries(mKind.mimeType)) {
    123             return false;
    124         }
    125 
    126         int editorCount = mEditors.getChildCount();
    127         for (int i = 0; i < editorCount; i++) {
    128             GenericEditorView editorView = (GenericEditorView) mEditors.getChildAt(i);
    129             if (editorView.isAnyFieldFilledOut()) {
    130                 return true;
    131             }
    132         }
    133 
    134         return false;
    135     }
    136 
    137     /**
    138      * Build editors for all current {@link #mState} rows.
    139      */
    140     public void rebuildFromState() {
    141         // Remove any existing editors
    142         mEditors.removeAllViews();
    143 
    144         // Check if we are displaying anything here
    145         boolean hasEntries = mState.hasMimeEntries(mKind.mimeType);
    146 
    147         if (!mKind.isList) {
    148             if (hasEntries) {
    149                 // we might have no visible entries. check that, too
    150                 for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
    151                     if (!entry.isVisible()) {
    152                         hasEntries = false;
    153                         break;
    154                     }
    155                 }
    156             }
    157 
    158             if (!hasEntries) {
    159                 EntityModifier.insertChild(mState, mKind);
    160                 hasEntries = true;
    161             }
    162         }
    163 
    164         if (hasEntries) {
    165             int entryIndex = 0;
    166             for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
    167                 // Skip entries that aren't visible
    168                 if (!entry.isVisible()) continue;
    169 
    170                 final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
    171                         R.layout.item_generic_editor, mEditors, false);
    172                 editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
    173                 // older versions of android had lists where we now have a single value
    174                 // in these cases we should show the remove button for all but the first value
    175                 // to ensure that nothing is removed
    176                 editor.mDelete.setVisibility((mKind.isList || (entryIndex != 0))
    177                         ? View.VISIBLE : View.GONE);
    178                 editor.setEditorListener(this);
    179                 mEditors.addView(editor);
    180                 entryIndex++;
    181             }
    182         }
    183     }
    184 
    185     protected void updateEditorsVisible() {
    186         final boolean hasChildren = mEditors.getChildCount() > 0;
    187         mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
    188     }
    189 
    190     protected void updateAddEnabled() {
    191         // Set enabled state on the "add" view
    192         final boolean canInsert = EntityModifier.canInsert(mState, mKind);
    193         final boolean isEnabled = !mReadOnly && canInsert;
    194         mAdd.setEnabled(isEnabled);
    195     }
    196 
    197     /** {@inheritDoc} */
    198     public void onClick(View v) {
    199         // if this is not a list the plus button is not visible but the user might have clicked
    200         // the text.
    201         if (!mKind.isList)
    202             return;
    203 
    204         // Insert a new child and rebuild
    205         final ValuesDelta newValues = EntityModifier.insertChild(mState, mKind);
    206         this.rebuildFromState();
    207         this.updateAddEnabled();
    208         this.updateEditorsVisible();
    209 
    210         // Find the newly added EditView and set focus.
    211         final int newFieldId = mViewIdGenerator.getId(mState, mKind, newValues, 0);
    212         final View newField = findViewById(newFieldId);
    213         if (newField != null) {
    214             newField.requestFocus();
    215         }
    216     }
    217 }
    218