1/* 2 * Copyright (C) 2006 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 17package android.widget; 18 19import android.content.Context; 20import android.database.Cursor; 21import android.net.Uri; 22import android.view.View; 23 24/** 25 * An easy adapter to map columns from a cursor to TextViews or ImageViews 26 * defined in an XML file. You can specify which columns you want, which views 27 * you want to display the columns, and the XML file that defines the appearance 28 * of these views. Separate XML files for child and groups are possible. 29 * 30 * Binding occurs in two phases. First, if a 31 * {@link android.widget.SimpleCursorTreeAdapter.ViewBinder} is available, 32 * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} 33 * is invoked. If the returned value is true, binding has occurred. If the 34 * returned value is false and the view to bind is a TextView, 35 * {@link #setViewText(TextView, String)} is invoked. If the returned value 36 * is false and the view to bind is an ImageView, 37 * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate 38 * binding can be found, an {@link IllegalStateException} is thrown. 39 */ 40public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter { 41 /** The indices of columns that contain data to display for a group. */ 42 private int[] mGroupFrom; 43 /** 44 * The View IDs that will display a group's data fetched from the 45 * corresponding column. 46 */ 47 private int[] mGroupTo; 48 49 /** The indices of columns that contain data to display for a child. */ 50 private int[] mChildFrom; 51 /** 52 * The View IDs that will display a child's data fetched from the 53 * corresponding column. 54 */ 55 private int[] mChildTo; 56 57 /** 58 * View binder, if supplied 59 */ 60 private ViewBinder mViewBinder; 61 62 /** 63 * Constructor. 64 * 65 * @param context The context where the {@link ExpandableListView} 66 * associated with this {@link SimpleCursorTreeAdapter} is 67 * running 68 * @param cursor The database cursor 69 * @param collapsedGroupLayout The resource identifier of a layout file that 70 * defines the views for a collapsed group. The layout file 71 * should include at least those named views defined in groupTo. 72 * @param expandedGroupLayout The resource identifier of a layout file that 73 * defines the views for an expanded group. The layout file 74 * should include at least those named views defined in groupTo. 75 * @param groupFrom A list of column names that will be used to display the 76 * data for a group. 77 * @param groupTo The group views (from the group layouts) that should 78 * display column in the "from" parameter. These should all be 79 * TextViews or ImageViews. The first N views in this list are 80 * given the values of the first N columns in the from parameter. 81 * @param childLayout The resource identifier of a layout file that defines 82 * the views for a child (except the last). The layout file 83 * should include at least those named views defined in childTo. 84 * @param lastChildLayout The resource identifier of a layout file that 85 * defines the views for the last child within a group. The 86 * layout file should include at least those named views defined 87 * in childTo. 88 * @param childFrom A list of column names that will be used to display the 89 * data for a child. 90 * @param childTo The child views (from the child layouts) that should 91 * display column in the "from" parameter. These should all be 92 * TextViews or ImageViews. The first N views in this list are 93 * given the values of the first N columns in the from parameter. 94 */ 95 public SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout, 96 int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout, 97 int lastChildLayout, String[] childFrom, int[] childTo) { 98 super(context, cursor, collapsedGroupLayout, expandedGroupLayout, childLayout, 99 lastChildLayout); 100 init(groupFrom, groupTo, childFrom, childTo); 101 } 102 103 /** 104 * Constructor. 105 * 106 * @param context The context where the {@link ExpandableListView} 107 * associated with this {@link SimpleCursorTreeAdapter} is 108 * running 109 * @param cursor The database cursor 110 * @param collapsedGroupLayout The resource identifier of a layout file that 111 * defines the views for a collapsed group. The layout file 112 * should include at least those named views defined in groupTo. 113 * @param expandedGroupLayout The resource identifier of a layout file that 114 * defines the views for an expanded group. The layout file 115 * should include at least those named views defined in groupTo. 116 * @param groupFrom A list of column names that will be used to display the 117 * data for a group. 118 * @param groupTo The group views (from the group layouts) that should 119 * display column in the "from" parameter. These should all be 120 * TextViews or ImageViews. The first N views in this list are 121 * given the values of the first N columns in the from parameter. 122 * @param childLayout The resource identifier of a layout file that defines 123 * the views for a child. The layout file 124 * should include at least those named views defined in childTo. 125 * @param childFrom A list of column names that will be used to display the 126 * data for a child. 127 * @param childTo The child views (from the child layouts) that should 128 * display column in the "from" parameter. These should all be 129 * TextViews or ImageViews. The first N views in this list are 130 * given the values of the first N columns in the from parameter. 131 */ 132 public SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout, 133 int expandedGroupLayout, String[] groupFrom, int[] groupTo, 134 int childLayout, String[] childFrom, int[] childTo) { 135 super(context, cursor, collapsedGroupLayout, expandedGroupLayout, childLayout); 136 init(groupFrom, groupTo, childFrom, childTo); 137 } 138 139 /** 140 * Constructor. 141 * 142 * @param context The context where the {@link ExpandableListView} 143 * associated with this {@link SimpleCursorTreeAdapter} is 144 * running 145 * @param cursor The database cursor 146 * @param groupLayout The resource identifier of a layout file that defines 147 * the views for a group. The layout file should include at least 148 * those named views defined in groupTo. 149 * @param groupFrom A list of column names that will be used to display the 150 * data for a group. 151 * @param groupTo The group views (from the group layouts) that should 152 * display column in the "from" parameter. These should all be 153 * TextViews or ImageViews. The first N views in this list are 154 * given the values of the first N columns in the from parameter. 155 * @param childLayout The resource identifier of a layout file that defines 156 * the views for a child. The layout file should include at least 157 * those named views defined in childTo. 158 * @param childFrom A list of column names that will be used to display the 159 * data for a child. 160 * @param childTo The child views (from the child layouts) that should 161 * display column in the "from" parameter. These should all be 162 * TextViews or ImageViews. The first N views in this list are 163 * given the values of the first N columns in the from parameter. 164 */ 165 public SimpleCursorTreeAdapter(Context context, Cursor cursor, int groupLayout, 166 String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, 167 int[] childTo) { 168 super(context, cursor, groupLayout, childLayout); 169 init(groupFrom, groupTo, childFrom, childTo); 170 } 171 172 private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames, 173 int[] childTo) { 174 mGroupTo = groupTo; 175 176 mChildTo = childTo; 177 178 // Get the group cursor column indices, the child cursor column indices will come 179 // when needed 180 initGroupFromColumns(groupFromNames); 181 182 // Get a temporary child cursor to init the column indices 183 if (getGroupCount() > 0) { 184 MyCursorHelper tmpCursorHelper = getChildrenCursorHelper(0, true); 185 if (tmpCursorHelper != null) { 186 initChildrenFromColumns(childFromNames, tmpCursorHelper.getCursor()); 187 deactivateChildrenCursorHelper(0); 188 } 189 } 190 } 191 192 private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) { 193 for (int i = fromColumnNames.length - 1; i >= 0; i--) { 194 fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]); 195 } 196 } 197 198 private void initGroupFromColumns(String[] groupFromNames) { 199 mGroupFrom = new int[groupFromNames.length]; 200 initFromColumns(mGroupCursorHelper.getCursor(), groupFromNames, mGroupFrom); 201 } 202 203 private void initChildrenFromColumns(String[] childFromNames, Cursor childCursor) { 204 mChildFrom = new int[childFromNames.length]; 205 initFromColumns(childCursor, childFromNames, mChildFrom); 206 } 207 208 /** 209 * Returns the {@link ViewBinder} used to bind data to views. 210 * 211 * @return a ViewBinder or null if the binder does not exist 212 * 213 * @see #setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder) 214 */ 215 public ViewBinder getViewBinder() { 216 return mViewBinder; 217 } 218 219 /** 220 * Sets the binder used to bind data to views. 221 * 222 * @param viewBinder the binder used to bind data to views, can be null to 223 * remove the existing binder 224 * 225 * @see #getViewBinder() 226 */ 227 public void setViewBinder(ViewBinder viewBinder) { 228 mViewBinder = viewBinder; 229 } 230 231 private void bindView(View view, Context context, Cursor cursor, int[] from, int[] to) { 232 final ViewBinder binder = mViewBinder; 233 234 for (int i = 0; i < to.length; i++) { 235 View v = view.findViewById(to[i]); 236 if (v != null) { 237 boolean bound = false; 238 if (binder != null) { 239 bound = binder.setViewValue(v, cursor, from[i]); 240 } 241 242 if (!bound) { 243 String text = cursor.getString(from[i]); 244 if (text == null) { 245 text = ""; 246 } 247 if (v instanceof TextView) { 248 setViewText((TextView) v, text); 249 } else if (v instanceof ImageView) { 250 setViewImage((ImageView) v, text); 251 } else { 252 throw new IllegalStateException("SimpleCursorTreeAdapter can bind values" + 253 " only to TextView and ImageView!"); 254 } 255 } 256 } 257 } 258 } 259 260 @Override 261 protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { 262 bindView(view, context, cursor, mChildFrom, mChildTo); 263 } 264 265 @Override 266 protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) { 267 bindView(view, context, cursor, mGroupFrom, mGroupTo); 268 } 269 270 /** 271 * Called by bindView() to set the image for an ImageView. By default, the 272 * value will be treated as a Uri. Intended to be overridden by Adapters 273 * that need to filter strings retrieved from the database. 274 * 275 * @param v ImageView to receive an image 276 * @param value the value retrieved from the cursor 277 */ 278 protected void setViewImage(ImageView v, String value) { 279 try { 280 v.setImageResource(Integer.parseInt(value)); 281 } catch (NumberFormatException nfe) { 282 v.setImageURI(Uri.parse(value)); 283 } 284 } 285 286 /** 287 * Called by bindView() to set the text for a TextView but only if 288 * there is no existing ViewBinder or if the existing ViewBinder cannot 289 * handle binding to an TextView. 290 * 291 * Intended to be overridden by Adapters that need to filter strings 292 * retrieved from the database. 293 * 294 * @param v TextView to receive text 295 * @param text the text to be set for the TextView 296 */ 297 public void setViewText(TextView v, String text) { 298 v.setText(text); 299 } 300 301 /** 302 * This class can be used by external clients of SimpleCursorTreeAdapter 303 * to bind values from the Cursor to views. 304 * 305 * You should use this class to bind values from the Cursor to views 306 * that are not directly supported by SimpleCursorTreeAdapter or to 307 * change the way binding occurs for views supported by 308 * SimpleCursorTreeAdapter. 309 * 310 * @see SimpleCursorTreeAdapter#setViewImage(ImageView, String) 311 * @see SimpleCursorTreeAdapter#setViewText(TextView, String) 312 */ 313 public static interface ViewBinder { 314 /** 315 * Binds the Cursor column defined by the specified index to the specified view. 316 * 317 * When binding is handled by this ViewBinder, this method must return true. 318 * If this method returns false, SimpleCursorTreeAdapter will attempts to handle 319 * the binding on its own. 320 * 321 * @param view the view to bind the data to 322 * @param cursor the cursor to get the data from 323 * @param columnIndex the column at which the data can be found in the cursor 324 * 325 * @return true if the data was bound to the view, false otherwise 326 */ 327 boolean setViewValue(View view, Cursor cursor, int columnIndex); 328 } 329} 330