/******************************************************************************* * Gaggle is Copyright 2010 by Geeksville Industries LLC, a California limited liability corporation. * * Gaggle is distributed under a dual license. We've chosen this approach because within Gaggle we've used a number * of components that Geeksville Industries LLC might reuse for commercial products. Gaggle can be distributed under * either of the two licenses listed below. * * 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. * * Commercial Distribution License * If you would like to distribute Gaggle (or portions thereof) under a license other than * the "GNU General Public License, version 2", contact Geeksville Industries. Geeksville Industries reserves * the right to release Gaggle source code under a commercial license of its choice. * * GNU Public License, version 2 * All other distribution of Gaggle must conform to the terms of the GNU Public License, version 2. The full * text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt. ******************************************************************************/ package com.geeksville.info; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ListView; import com.geeksville.gaggle.R; /** * A vertical list of info docks * * @author kevinh * */ public class InfoListView extends ListView { private static final String TAG = "InfoListView"; private static final String[] classNames = { "com.geeksville.info.InfoVerticalSpeed", "com.geeksville.info.InfoGlideRatio", "com.geeksville.info.InfoAltitude", "com.geeksville.info.InfoGroundSpeed", "com.geeksville.info.InfoDistWaypoint", "com.geeksville.info.InfoGRWaypoint", "com.geeksville.info.InfoNearestLZ", "com.geeksville.info.InfoGRNearestLZ", "com.geeksville.info.InfoCompass", "com.geeksville.info.InfoLatitude", "com.geeksville.info.InfoLongitude", "com.geeksville.info.InfoGMeter", "com.geeksville.info.InfoBarometer", }; private ArrayList<String> shownNames = new ArrayList<String>(); private Set<String> checkedNames = new HashSet<String>(); private CheckedDockAdapter adapter; private int rowLayoutId; public InfoListView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.InfoListView); // default to a wide layout unless the user asked for something else rowLayoutId = arr.getResourceId(R.styleable.InfoListView_row_layout_id, R.layout.infodock_list_row); setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); setAdapter(adapter = new CheckedDockAdapter(context)); // Unless we know otherwise assume we want all selected for (String s : classNames) checkedNames.add(s); setShowCheckmarks(false); setShowUncheckedRows(false); setFocusable(false); } public String[] getChecked() { String[] result = new String[checkedNames.size()]; result = checkedNames.toArray(result); return result; } public void setChecked(String[] checked) { checkedNames.clear(); for (String s : checked) checkedNames.add(s); updateShownNames(); } void setShowCheckmarks(boolean showCheckmarks) { this.showCheckmarks = showCheckmarks; requestLayout(); } boolean isShowCheckmarks() { return showCheckmarks; } private void updateShownNames() { shownNames.clear(); for (String name : classNames) // We do it this way because we want to // preserve ordering if (showUncheckedRows || checkedNames.contains(name)) shownNames.add(name); adapter.notifyDataSetChanged(); } void setShowUncheckedRows(boolean showUncheckedRows) { this.showUncheckedRows = showUncheckedRows; updateShownNames(); } boolean isShowUncheckedRows() { return showUncheckedRows; } private boolean showCheckmarks = false; private boolean showUncheckedRows = false; /** * generate an optionally checkable set of info docks * * @author kevinh * */ private class CheckedDockAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener { LayoutInflater inflater; public CheckedDockAdapter(Context context) { inflater = (LayoutInflater) context .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); } /** * Click the checkbox for included items, and place the infofields in the * docks * * @see android.widget.ArrayAdapter#getView(int, android.view.View, * android.view.ViewGroup) */ @Override public View getView(int position, View convertView, ViewGroup parent) { // Let's reuse old rows if we can View row; if (convertView != null) row = convertView; else row = inflater.inflate(rowLayoutId, null); // Put the field into our dock, but work in the IDE try { InfoDock dock = (InfoDock) row.findViewById(R.id.info); String name = (String) getItem(position); boolean isChecked = checkedNames.contains(name); dock.setInfoField(name); boolean isValid = dock.isEnabled(); // false if we couldn't make // the info field if (!isValid) checkedNames.remove(name); CheckBox checkbox = (CheckBox) row.findViewById(R.id.checkbox); checkbox.setEnabled(isValid); checkbox.setChecked(isValid && isChecked); checkbox.setVisibility(isShowCheckmarks() ? VISIBLE : GONE); checkbox.setTag(name); checkbox.setOnCheckedChangeListener(this); } catch (ClassCastException ex) { Log.w(TAG, "Ignoring " + ex.getMessage()); } return row; } @Override public int getCount() { return shownNames.size(); } @Override public Object getItem(int position) { return shownNames.get(position); } @Override public long getItemId(int position) { return position; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { String name = (String) buttonView.getTag(); if (isChecked) checkedNames.add(name); else checkedNames.remove(name); } } }