Home | History | Annotate | Download | only in widget
      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 
     17 package android.widget;
     18 
     19 import android.content.Context;
     20 import android.database.Cursor;
     21 import android.net.Uri;
     22 import 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  */
     40 public 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