/* * AndFHEM - Open Source Android application to control a FHEM home automation * server. * * Copyright (c) 2011, Matthias Klass or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. * * 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 distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package li.klass.fhem.widget; import android.content.Context; import android.database.DataSetObserver; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListAdapter; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static com.google.common.collect.Maps.newHashMap; public abstract class NestedListViewAdapter<P, C> extends BaseAdapter implements ListAdapter { protected Set<NestedListView.NestedListViewOnClickObserver> parentChildClickObservers = new HashSet<NestedListView.NestedListViewOnClickObserver>(); protected LayoutInflater layoutInflater; private Map<Integer, P> parentPositions = newHashMap(); private int totalItems = 0; public NestedListViewAdapter(Context context) { layoutInflater = LayoutInflater.from(context); } @Override public View getView(int flatPosition, View view, ViewGroup viewGroup) { try { if (isParent(flatPosition)) { P parent = parentPositions.get(flatPosition); return getParentView(parent, view, viewGroup); } else { int parentPosition = findParentPositionForChildPosition(flatPosition); P parent = parentPositions.get(parentPosition); int relativeChildPosition = flatPosition - parentPosition - 1; C child = getChildForParentAndChildPosition(parent, relativeChildPosition); return getChildView(parent, parentPosition, child, view, viewGroup, relativeChildPosition); } } catch (Exception e) { Log.e(NestedListViewAdapter.class.getName(), "error occurred", e); return null; } } public boolean isParent(int position) { return parentPositions.containsKey(position); } protected abstract View getParentView(P parent, View view, ViewGroup viewGroup); public int findParentPositionForChildPosition(int flatPosition) { Set<Integer> keyPositions = parentPositions.keySet(); int bestKeyMatch = 0; int bestKeyDiff = -1; for (int keyPosition : keyPositions) { int diff = flatPosition - keyPosition; if (diff >= 0 && (bestKeyDiff == -1 || diff < bestKeyDiff)) { bestKeyDiff = diff; bestKeyMatch = keyPosition; } } return bestKeyMatch; } protected abstract C getChildForParentAndChildPosition(P parent, int childPosition); protected abstract View getChildView(P parent, int parentPosition, C child, View view, ViewGroup viewGroup, int relativeChildPosition); public int findOriginalParentPosition(int flatPosition) { P parent; if (isParent(flatPosition)) { parent = parentPositions.get(flatPosition); } else { parent = parentPositions.get(findParentPositionForChildPosition(flatPosition)); } List<P> parents = getParents(); for (int i = 0; i < parents.size(); i++) { if (parents.get(i).equals(parent)) { return i; } } return -1; } protected abstract List<P> getParents(); public int getCount() { return totalItems; } public Object getItem(int position) { if (isParent(position)) { return parentPositions.get(position); } else { int parentPosition = findParentPositionForChildPosition(position); P parent = parentPositions.get(parentPosition); int relativeChildPosition = position - parentPosition; return getChildForParentAndChildPosition(parent, relativeChildPosition); } } public long getItemId(int i) { return i; } protected void updateData() { updateParentPositions(); notifyDataSetChanged(); } public void updateParentPositions() { parentPositions = newHashMap(); int currentPosition = 0; for (P item : getParents()) { parentPositions.put(currentPosition, item); currentPosition += getChildrenCountForParent(item); currentPosition++; } totalItems = currentPosition; } protected abstract int getChildrenCountForParent(P parent); public void addParentChildObserver(NestedListView.NestedListViewOnClickObserver observer) { parentChildClickObservers.add(observer); } public void removeParentChildObserver(NestedListView.NestedListViewOnClickObserver observer) { parentChildClickObservers.remove(observer); } @Override public boolean isEmpty() { return totalItems == 0; } @Override public void unregisterDataSetObserver(DataSetObserver observer) { // Workaround for a silly bug in Android 4 // see http://code.google.com/p/android/issues/detail?id=22946 for details if (observer != null) { super.unregisterDataSetObserver(observer); } } }