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