package edu.mit.mobile.android.widget;
/*
* Copyright (C) 2010 MIT Mobile Experience Lab
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* Parts Copyright (C) 2006 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.
*/
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import edu.mit.mobile.android.locast.ver2.R;
/**
* Displays a list of views representing the contents of the adapter.
* Shows all views at once and sizes them relative to one another based on the value of
* getRelativeSize()
*
* @author steve
*
*/
public class RelativeSizeListView extends AdapterView<RelativeSizeListAdapter> implements OnClickListener {
private RelativeSizeListAdapter mAdapter;
private int mSelectedPosition = INVALID_POSITION;
private long mSelectedRowId = INVALID_ROW_ID;
private DataSetObserver mDataSetObserver;
private int mItemCount;
private int mRelMax;
private float mMinWidth;
private final LinearLayout mLinearLayout;
private static int TAG_ITEM_POSITION = R.id.tag; // XXX not entirely kosher, but should work.
public RelativeSizeListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
setWillNotDraw(true);
mLinearLayout = new LinearLayout(context, attrs);
mLinearLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
public RelativeSizeListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RelativeSizeListView(Context context) {
this(context, null);
}
@Override
public RelativeSizeListAdapter getAdapter() {
return mAdapter;
}
@Override
public View getSelectedView() {
if (mItemCount > 0 && mSelectedPosition != INVALID_POSITION){
return getChildAt(mSelectedPosition);
}else{
return null;
}
}
@Override
public Object getSelectedItem() {
if (mItemCount > 0 && mSelectedPosition != INVALID_POSITION){
return mAdapter.getItem(mSelectedPosition);
}else{
return null;
}
}
@Override
public long getSelectedItemId() {
return mSelectedRowId;
}
@Override
public int getSelectedItemPosition() {
return mSelectedPosition;
}
@Override
public int getCount() {
return mItemCount;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
requestLayout();
}
public void setMinWidth(float minWidth){
mMinWidth = minWidth;
requestLayout();
}
@Override
public void setAdapter(RelativeSizeListAdapter adapter) {
if (mAdapter != null){
mAdapter.unregisterDataSetObserver(mDataSetObserver);
resetList();
}
mAdapter = adapter;
if (mAdapter != null){
updateCached();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
}else{
resetList();
}
requestLayout();
}
@Override
public void setSelection(int position) {
mSelectedPosition = position;
if (position != INVALID_POSITION){
mSelectedRowId = mAdapter.getItemId(position);
}else{
mSelectedRowId = INVALID_ROW_ID;
}
requestLayout();
invalidate();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mAdapter == null){
return;
}
if (getChildCount() == 0){
addViewInLayout(mLinearLayout, -1, new AdapterView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT), true);
}
final int currentCount = mLinearLayout.getChildCount();
final boolean enabled = isEnabled();
// first remove any views
mLinearLayout.removeViews(0, Math.max(0, currentCount - mItemCount));
for (int i = 0; i < mItemCount; i++){
final View existingView = i < currentCount ? mLinearLayout.getChildAt(i): null;
final View child = mAdapter.getView(i, existingView, mLinearLayout);
child.setTag(TAG_ITEM_POSITION, i);
child.setSelected(mSelectedPosition == i);
child.setEnabled(enabled);
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
child.setLayoutParams(params);
(params).weight = mRelMax - mAdapter.getRelativeSize(i);
if (existingView == null){
child.setOnClickListener(this);
mLinearLayout.addView(child);
}
}
mLinearLayout.measure(MeasureSpec.EXACTLY | right - left, MeasureSpec.EXACTLY | bottom - top);
mLinearLayout.layout(0, 0, right-left, bottom-top);
}
private void resetList(){
mLinearLayout.removeAllViews();
mSelectedPosition = INVALID_POSITION;
mSelectedRowId = INVALID_ROW_ID;
invalidate();
}
private void updateCached(){
mItemCount = mAdapter.getCount();
mRelMax = 0;
for (int i = 0; i < mItemCount; i++){
mRelMax += mAdapter.getRelativeSize(i);
}
}
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
updateCached();
requestLayout();
}
@Override
public void onInvalidated() {
mItemCount = 0;
resetList();
}
}
@Override
public void onClick(View v) {
final Integer position = (Integer) v.getTag(TAG_ITEM_POSITION);
performItemClick(v, position, getItemIdAtPosition(position));
}
}