public class

KindSectionView

extends LinearLayout
implements View.OnClickListener Editor.EditorListener
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.contacts.ui.widget;

import com.android.contacts.R;
import com.android.contacts.model.Editor;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityModifier;
import com.android.contacts.model.ContactsSource.DataKind;
import com.android.contacts.model.Editor.EditorListener;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.ui.ViewIdGenerator;

import android.content.Context;
import android.provider.ContactsContract.Data;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * Custom view for an entire section of data as segmented by
 * {@link DataKind} around a {@link Data#MIMETYPE}. This view shows a
 * section header and a trigger for adding new {@link Data} rows.
 */
public class KindSectionView extends LinearLayout implements OnClickListener, EditorListener {
    private static final String TAG = "KindSectionView";

    private LayoutInflater mInflater;

    private ViewGroup mEditors;
    private View mAdd;
    private ImageView mAddPlusButton;
    private TextView mTitle;

    private DataKind mKind;
    private EntityDelta mState;
    private boolean mReadOnly;

    private ViewIdGenerator mViewIdGenerator;

    public KindSectionView(Context context) {
        super(context);
    }

    public KindSectionView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /** {@inheritDoc} */
    @Override
    protected void onFinishInflate() {
        mInflater = (LayoutInflater)getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);

        setDrawingCacheEnabled(true);
        setAlwaysDrawnWithCacheEnabled(true);

        mEditors = (ViewGroup)findViewById(R.id.kind_editors);

        mAdd = findViewById(R.id.kind_header);
        mAdd.setOnClickListener(this);

        mAddPlusButton = (ImageView) findViewById(R.id.kind_plus);

        mTitle = (TextView)findViewById(R.id.kind_title);
    }

    /** {@inheritDoc} */
    public void onDeleted(Editor editor) {
        this.updateAddEnabled();
        this.updateEditorsVisible();
    }

    /** {@inheritDoc} */
    public void onRequest(int request) {
        // Ignore requests
    }

    public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) {
        mKind = kind;
        mState = state;
        mReadOnly = readOnly;
        mViewIdGenerator = vig;

        setId(mViewIdGenerator.getId(state, kind, null, ViewIdGenerator.NO_VIEW_INDEX));

        // TODO: handle resources from remote packages
        mTitle.setText(kind.titleRes);

        // Only show the add button if this is a list
        mAddPlusButton.setVisibility(mKind.isList ? View.VISIBLE : View.GONE);

        this.rebuildFromState();
        this.updateAddEnabled();
        this.updateEditorsVisible();
    }

    public boolean isAnyEditorFilledOut() {
        if (mState == null) {
            return false;
        }

        if (!mState.hasMimeEntries(mKind.mimeType)) {
            return false;
        }

        int editorCount = mEditors.getChildCount();
        for (int i = 0; i < editorCount; i++) {
            GenericEditorView editorView = (GenericEditorView) mEditors.getChildAt(i);
            if (editorView.isAnyFieldFilledOut()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Build editors for all current {@link #mState} rows.
     */
    public void rebuildFromState() {
        // Remove any existing editors
        mEditors.removeAllViews();

        // Check if we are displaying anything here
        boolean hasEntries = mState.hasMimeEntries(mKind.mimeType);

        if (!mKind.isList) {
            if (hasEntries) {
                // we might have no visible entries. check that, too
                for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
                    if (!entry.isVisible()) {
                        hasEntries = false;
                        break;
                    }
                }
            }

            if (!hasEntries) {
                EntityModifier.insertChild(mState, mKind);
                hasEntries = true;
            }
        }

        if (hasEntries) {
            int entryIndex = 0;
            for (ValuesDelta entry : mState.getMimeEntries(mKind.mimeType)) {
                // Skip entries that aren't visible
                if (!entry.isVisible()) continue;

                final GenericEditorView editor = (GenericEditorView)mInflater.inflate(
                        R.layout.item_generic_editor, mEditors, false);
                editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
                // older versions of android had lists where we now have a single value
                // in these cases we should show the remove button for all but the first value
                // to ensure that nothing is removed
                editor.mDelete.setVisibility((mKind.isList || (entryIndex != 0))
                        ? View.VISIBLE : View.GONE);
                editor.setEditorListener(this);
                mEditors.addView(editor);
                entryIndex++;
            }
        }
    }

    protected void updateEditorsVisible() {
        final boolean hasChildren = mEditors.getChildCount() > 0;
        mEditors.setVisibility(hasChildren ? View.VISIBLE : View.GONE);
    }

    protected void updateAddEnabled() {
        // Set enabled state on the "add" view
        final boolean canInsert = EntityModifier.canInsert(mState, mKind);
        final boolean isEnabled = !mReadOnly && canInsert;
        mAdd.setEnabled(isEnabled);
    }

    /** {@inheritDoc} */
    public void onClick(View v) {
        // if this is not a list the plus button is not visible but the user might have clicked
        // the text.
        if (!mKind.isList)
            return;

        // Insert a new child and rebuild
        final ValuesDelta newValues = EntityModifier.insertChild(mState, mKind);
        this.rebuildFromState();
        this.updateAddEnabled();
        this.updateEditorsVisible();

        // Find the newly added EditView and set focus.
        final int newFieldId = mViewIdGenerator.getId(mState, mKind, newValues, 0);
        final View newField = findViewById(newFieldId);
        if (newField != null) {
            newField.requestFocus();
        }
    }
}