content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.widget;
  
  import android.content.Context;
  import android.database.Cursor;
  import android.net.Uri;
  import android.view.View;
  
  /**
   * An easy adapter to map columns from a cursor to TextViews or ImageViews
   * defined in an XML file. You can specify which columns you want, which views
   * you want to display the columns, and the XML file that defines the appearance
   * of these views. Separate XML files for child and groups are possible.
   *
   * Binding occurs in two phases. First, if a
   * {@link android.widget.SimpleCursorTreeAdapter.ViewBinder} is available,
   * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
   * is invoked. If the returned value is true, binding has occurred. If the
   * returned value is false and the view to bind is a TextView,
   * {@link #setViewText(TextView, String)} is invoked. If the returned value
   * is false and the view to bind is an ImageView,
   * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
   * binding can be found, an {@link IllegalStateException} is thrown.
   */
  public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
      
      /** The name of the columns that contain the data to display for a group. */
      private String[] mGroupFromNames;
      
      /** The indices of columns that contain data to display for a group. */
      private int[] mGroupFrom;
      /**
       * The View IDs that will display a group's data fetched from the
       * corresponding column.
       */
      private int[] mGroupTo;
  
      /** The name of the columns that contain the data to display for a child. */
      private String[] mChildFromNames;
      
      /** The indices of columns that contain data to display for a child. */
      private int[] mChildFrom;
      /**
       * The View IDs that will display a child's data fetched from the
       * corresponding column.
       */
      private int[] mChildTo;
      
      /**
       * View binder, if supplied
       */
      private ViewBinder mViewBinder;
  
      /**
       * Constructor.
       * 
       * @param context The context where the {@link ExpandableListView}
       *            associated with this {@link SimpleCursorTreeAdapter} is
       *            running
       * @param cursor The database cursor
       * @param collapsedGroupLayout The resource identifier of a layout file that
       *            defines the views for a collapsed group. The layout file
       *            should include at least those named views defined in groupTo.
       * @param expandedGroupLayout The resource identifier of a layout file that
       *            defines the views for an expanded group. The layout file
       *            should include at least those named views defined in groupTo.
       * @param groupFrom A list of column names that will be used to display the
       *            data for a group.
       * @param groupTo The group views (from the group layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       * @param childLayout The resource identifier of a layout file that defines
       *            the views for a child (except the last). The layout file
       *            should include at least those named views defined in childTo.
       * @param lastChildLayout The resource identifier of a layout file that
       *            defines the views for the last child within a group. The
       *            layout file should include at least those named views defined
       *            in childTo.
       * @param childFrom A list of column names that will be used to display the
       *            data for a child.
       * @param childTo The child views (from the child layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       */
      public SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout,
              int expandedGroupLayout, String[] groupFrom, int[] groupTo, int childLayout,
              int lastChildLayout, String[] childFrom, int[] childTo) {
          super(context, cursor, collapsedGroupLayout, expandedGroupLayout, childLayout,
                  lastChildLayout);
          init(groupFrom, groupTo, childFrom, childTo);
      }
  
      /**
       * Constructor.
       * 
       * @param context The context where the {@link ExpandableListView}
       *            associated with this {@link SimpleCursorTreeAdapter} is
       *            running
       * @param cursor The database cursor
       * @param collapsedGroupLayout The resource identifier of a layout file that
       *            defines the views for a collapsed group. The layout file
       *            should include at least those named views defined in groupTo.
       * @param expandedGroupLayout The resource identifier of a layout file that
       *            defines the views for an expanded group. The layout file
       *            should include at least those named views defined in groupTo.
       * @param groupFrom A list of column names that will be used to display the
       *            data for a group.
       * @param groupTo The group views (from the group layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       * @param childLayout The resource identifier of a layout file that defines
       *            the views for a child. The layout file
       *            should include at least those named views defined in childTo.
       * @param childFrom A list of column names that will be used to display the
       *            data for a child.
       * @param childTo The child views (from the child layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       */
      public SimpleCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout,
              int expandedGroupLayout, String[] groupFrom, int[] groupTo,
              int childLayout, String[] childFrom, int[] childTo) {
          super(context, cursor, collapsedGroupLayout, expandedGroupLayout, childLayout);
          init(groupFrom, groupTo, childFrom, childTo);
      }
  
      /**
       * Constructor.
       * 
       * @param context The context where the {@link ExpandableListView}
       *            associated with this {@link SimpleCursorTreeAdapter} is
       *            running
       * @param cursor The database cursor
       * @param groupLayout The resource identifier of a layout file that defines
       *            the views for a group. The layout file should include at least
       *            those named views defined in groupTo.
       * @param groupFrom A list of column names that will be used to display the
       *            data for a group.
       * @param groupTo The group views (from the group layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       * @param childLayout The resource identifier of a layout file that defines
       *            the views for a child. The layout file should include at least
       *            those named views defined in childTo.
       * @param childFrom A list of column names that will be used to display the
       *            data for a child.
       * @param childTo The child views (from the child layouts) that should
       *            display column in the "from" parameter. These should all be
       *            TextViews or ImageViews. The first N views in this list are
       *            given the values of the first N columns in the from parameter.
       */
      public SimpleCursorTreeAdapter(Context context, Cursor cursor, int groupLayout,
              String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom,
              int[] childTo) {
          super(context, cursor, groupLayout, childLayout);
          init(groupFrom, groupTo, childFrom, childTo);
      }
  
      private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames,
              int[] childTo) {
          
          mGroupFromNames = groupFromNames;
          mGroupTo = groupTo;
          
          mChildFromNames = childFromNames;
          mChildTo = childTo;
      }
      
      /**
       * Returns the {@link ViewBinder} used to bind data to views.
       *
       * @return a ViewBinder or null if the binder does not exist
       *
       * @see #setViewBinder(android.widget.SimpleCursorTreeAdapter.ViewBinder)
       */
      public ViewBinder getViewBinder() {
          return mViewBinder;
      }
  
      /**
       * Sets the binder used to bind data to views.
       *
       * @param viewBinder the binder used to bind data to views, can be null to
       *        remove the existing binder
       *
       * @see #getViewBinder()
       */
      public void setViewBinder(ViewBinder viewBinder) {
          mViewBinder = viewBinder;
      }
  
      private void bindView(View view, Context context, Cursor cursor, int[] from, int[] to) {
          final ViewBinder binder = mViewBinder;
          
          for (int i = 0; i < to.length; i++) {
              View v = view.findViewById(to[i]);
              if (v != null) {
                  boolean bound = false;
                  if (binder != null) {
                      bound = binder.setViewValue(v, cursor, from[i]);
                  }
                  
                  if (!bound) {
                      String text = cursor.getString(from[i]);
                      if (text == null) {
                          text = "";
                      }
                      if (v instanceof TextView) {
                          setViewText((TextView) v, text);
                      } else if (v instanceof ImageView) {
                          setViewImage((ImageView) v, text);
                      } else {
                          throw new IllegalStateException("SimpleCursorTreeAdapter can bind values" +
                                  " only to TextView and ImageView!");
                      }
                  }
              }
          }
      }
      
      private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
          for (int i = fromColumnNames.length - 1; i >= 0; i--) {
              fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
          }
      }
      
      @Override
      protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
          if (mChildFrom == null) {
              mChildFrom = new int[mChildFromNames.length];
              initFromColumns(cursor, mChildFromNames, mChildFrom);
          }
          
          bindView(view, context, cursor, mChildFrom, mChildTo);
      }
  
      @Override
      protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
          if (mGroupFrom == null) {
              mGroupFrom = new int[mGroupFromNames.length];
              initFromColumns(cursor, mGroupFromNames, mGroupFrom);
          }
          
          bindView(view, context, cursor, mGroupFrom, mGroupTo);
      }
  
      /**
       * Called by bindView() to set the image for an ImageView. By default, the
       * value will be treated as a Uri. Intended to be overridden by Adapters
       * that need to filter strings retrieved from the database.
       * 
       * @param v ImageView to receive an image
       * @param value the value retrieved from the cursor
       */
      protected void setViewImage(ImageView v, String value) {
          try {
              v.setImageResource(Integer.parseInt(value));
          } catch (NumberFormatException nfe) {
              v.setImageURI(Uri.parse(value));
          }
      }
  
      /**
       * Called by bindView() to set the text for a TextView but only if
       * there is no existing ViewBinder or if the existing ViewBinder cannot
       * handle binding to a TextView.
       *
       * Intended to be overridden by Adapters that need to filter strings
       * retrieved from the database.
       * 
       * @param v TextView to receive text
       * @param text the text to be set for the TextView
       */
      public void setViewText(TextView v, String text) {
          v.setText(text);
      }
  
      /**
       * This class can be used by external clients of SimpleCursorTreeAdapter
       * to bind values from the Cursor to views.
       *
       * You should use this class to bind values from the Cursor to views
       * that are not directly supported by SimpleCursorTreeAdapter or to
       * change the way binding occurs for views supported by
       * SimpleCursorTreeAdapter.
       *
       * @see SimpleCursorTreeAdapter#setViewImage(ImageView, String) 
       * @see SimpleCursorTreeAdapter#setViewText(TextView, String)
       */
      public static interface ViewBinder {
          /**
           * Binds the Cursor column defined by the specified index to the specified view.
           *
           * When binding is handled by this ViewBinder, this method must return true.
           * If this method returns false, SimpleCursorTreeAdapter will attempts to handle
           * the binding on its own.
           *
           * @param view the view to bind the data to
           * @param cursor the cursor to get the data from
           * @param columnIndex the column at which the data can be found in the cursor
           *
           * @return true if the data was bound to the view, false otherwise
           */
          boolean setViewValue(View view, Cursor cursor, int columnIndex);
      }
  }
  