160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov/*
260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project
360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov *
460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * you may not use this file except in compliance with the License.
660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * You may obtain a copy of the License at
760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov *
860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov *
1060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
1160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
1260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * See the License for the specific language governing permissions and
1460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * limitations under the License.
1560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov */
1660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovpackage com.android.common.widget;
1760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
1860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovimport android.content.Context;
1960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovimport android.database.Cursor;
2060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovimport android.view.View;
2160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovimport android.view.ViewGroup;
2260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovimport android.widget.BaseAdapter;
2360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
249a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albertimport java.util.ArrayList;
259a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert
2660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov/**
2760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * A general purpose adapter that is composed of multiple cursors. It just
2860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov * appends them in the order they are added.
2960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov */
3060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikovpublic abstract class CompositeCursorAdapter extends BaseAdapter {
3160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
3260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    private static final int INITIAL_CAPACITY = 2;
3360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
3460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public static class Partition {
3560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        boolean showIfEmpty;
3660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        boolean hasHeader;
3760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
3860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        Cursor cursor;
3960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int idColumnIndex;
4060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int count;
4160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
4260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        public Partition(boolean showIfEmpty, boolean hasHeader) {
4360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            this.showIfEmpty = showIfEmpty;
4460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            this.hasHeader = hasHeader;
4560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
4660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
4760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        /**
4860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov         * True if the directory should be shown even if no contacts are found.
4960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov         */
5060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        public boolean getShowIfEmpty() {
5160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            return showIfEmpty;
5260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
5360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
5460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        public boolean getHasHeader() {
5560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            return hasHeader;
5660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
57e93a23581cbb9da2282b5897ffc167f86836afaeNancy Chen
58e93a23581cbb9da2282b5897ffc167f86836afaeNancy Chen        public boolean isEmpty() {
59e93a23581cbb9da2282b5897ffc167f86836afaeNancy Chen            return count == 0;
60e93a23581cbb9da2282b5897ffc167f86836afaeNancy Chen        }
6160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
6260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
6360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    private final Context mContext;
649a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert    private ArrayList<Partition> mPartitions;
6560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    private int mCount = 0;
6660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    private boolean mCacheValid = true;
6755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    private boolean mNotificationsEnabled = true;
6855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    private boolean mNotificationNeeded;
6960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
7060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public CompositeCursorAdapter(Context context) {
7160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        this(context, INITIAL_CAPACITY);
7260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
7360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
7460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public CompositeCursorAdapter(Context context, int initialCapacity) {
7560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        mContext = context;
769a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions = new ArrayList<Partition>();
7760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
7860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
7960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public Context getContext() {
8060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return mContext;
8160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
8260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
8360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
8460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Registers a partition. The cursor for that partition can be set later.
8560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Partitions should be added in the order they are supposed to appear in the
8660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * list.
8760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
8860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void addPartition(boolean showIfEmpty, boolean hasHeader) {
8960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        addPartition(new Partition(showIfEmpty, hasHeader));
9060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
9160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
9260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void addPartition(Partition partition) {
939a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.add(partition);
949a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        invalidate();
959a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        notifyDataSetChanged();
969a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert    }
979a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert
989a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert    public void addPartition(int location, Partition partition) {
999a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.add(location, partition);
10060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        invalidate();
10160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        notifyDataSetChanged();
10260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
10360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
10460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void removePartition(int partitionIndex) {
1059a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        Cursor cursor = mPartitions.get(partitionIndex).cursor;
10660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        if (cursor != null && !cursor.isClosed()) {
10760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            cursor.close();
10860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
1099a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.remove(partitionIndex);
11060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        invalidate();
11160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        notifyDataSetChanged();
11260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
11360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
11460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
11560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Removes cursors for all partitions.
11660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
117e93a23581cbb9da2282b5897ffc167f86836afaeNancy Chen    // TODO: Is this really what this is supposed to do? Just remove the cursors? Not close them?
1189a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert    // Not remove the partitions themselves? Isn't this leaking?
1199a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert
12060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void clearPartitions() {
1219a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition partition : mPartitions) {
1229a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            partition.cursor = null;
12360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
12460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        invalidate();
12560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        notifyDataSetChanged();
12660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
12760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
1285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
1295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Closes all cursors and removes all partitions.
1305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
1315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public void close() {
1329a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition partition : mPartitions) {
1339a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            Cursor cursor = partition.cursor;
1345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (cursor != null && !cursor.isClosed()) {
1355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                cursor.close();
1365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
1375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
1389a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.clear();
1395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        invalidate();
1405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        notifyDataSetChanged();
1415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
1425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
14360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void setHasHeader(int partitionIndex, boolean flag) {
1449a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.get(partitionIndex).hasHeader = flag;
14560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        invalidate();
14660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
14760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
14860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void setShowIfEmpty(int partitionIndex, boolean flag) {
1499a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        mPartitions.get(partitionIndex).showIfEmpty = flag;
15060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        invalidate();
15160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
15260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
15360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public Partition getPartition(int partitionIndex) {
1549a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        return mPartitions.get(partitionIndex);
15560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
15660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
15760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected void invalidate() {
15860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        mCacheValid = false;
15960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
16060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
16160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getPartitionCount() {
1629a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        return mPartitions.size();
16360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
16460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
16560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected void ensureCacheValid() {
16660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        if (mCacheValid) {
16760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            return;
16860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
16960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
17060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        mCount = 0;
1719a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition partition : mPartitions) {
1729a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            Cursor cursor = partition.cursor;
17360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            int count = cursor != null ? cursor.getCount() : 0;
1749a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            if (partition.hasHeader) {
1759a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (count != 0 || partition.showIfEmpty) {
17660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    count++;
17760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
17860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
1799a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            partition.count = count;
18060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            mCount += count;
18160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
18260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
18360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        mCacheValid = true;
18460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
18560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
18660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
18760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns true if the specified partition was configured to have a header.
18860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
18960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public boolean hasHeader(int partition) {
1909a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        return mPartitions.get(partition).hasHeader;
19160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
19260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
19360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
19460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the total number of list items in all partitions.
19560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
19660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getCount() {
19760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
19860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return mCount;
19960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
20060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
20160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
20260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the cursor for the given partition
20360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
20460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public Cursor getCursor(int partition) {
2059a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        return mPartitions.get(partition).cursor;
20660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
20760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
20860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
20960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Changes the cursor for an individual partition.
21060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
21160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public void changeCursor(int partition, Cursor cursor) {
2129a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        Cursor prevCursor = mPartitions.get(partition).cursor;
21360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        if (prevCursor != cursor) {
21460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (prevCursor != null && !prevCursor.isClosed()) {
21560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                prevCursor.close();
21660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
2179a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            mPartitions.get(partition).cursor = cursor;
21860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (cursor != null) {
2199a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                mPartitions.get(partition).idColumnIndex = cursor.getColumnIndex("_id");
22060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
22160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            invalidate();
22260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            notifyDataSetChanged();
22360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
22460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
22560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
22660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
22760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns true if the specified partition has no cursor or an empty cursor.
22860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
22960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public boolean isPartitionEmpty(int partition) {
2309a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        Cursor cursor = mPartitions.get(partition).cursor;
23160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return cursor == null || cursor.getCount() == 0;
23260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
23360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
23460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
23560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Given a list position, returns the index of the corresponding partition.
23660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
23760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getPartitionForPosition(int position) {
23860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
23960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
2409a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (int i = 0, n = mPartitions.size(); i < n; i++) {
2419a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + mPartitions.get(i).count;
24260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
24360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                return i;
24460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
24560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
24660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
24760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return -1;
24860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
24960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
25060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
25160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Given a list position, return the offset of the corresponding item in its
25260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * partition.  The header, if any, will have offset -1.
25360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
25460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getOffsetInPartition(int position) {
25560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
25660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
2579a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition partition : mPartitions) {
2589a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + partition.count;
25960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
26060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
2619a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (partition.hasHeader) {
26260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    offset--;
26360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
26460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                return offset;
26560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
26660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
26760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
26860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return -1;
26960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
27060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
27160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
27260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the first list position for the specified partition.
27360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
27460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getPositionForPartition(int partition) {
27560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
27660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int position = 0;
27760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        for (int i = 0; i < partition; i++) {
2789a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            position += mPartitions.get(i).count;
27960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
28060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return position;
28160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
28260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
28360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    @Override
28460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getViewTypeCount() {
28560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return getItemViewTypeCount() + 1;
28660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
28760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
28860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
28960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the overall number of item view types across all partitions. An
29060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * implementation of this method needs to ensure that the returned count is
29160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * consistent with the values returned by {@link #getItemViewType(int,int)}.
29260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
29360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getItemViewTypeCount() {
29460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return 1;
29560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
29660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
29760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
29860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the view type for the list item at the specified position in the
29960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * specified partition.
30060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
30160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected int getItemViewType(int partition, int position) {
30260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return 1;
30360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
30460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
30560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    @Override
30660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public int getItemViewType(int position) {
30760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
30860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
3099a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (int i = 0, n = mPartitions.size(); i < n; i++) {
3109a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start  + mPartitions.get(i).count;
31160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
31260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
3139a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartitions.get(i).hasHeader) {
31453f35c7c31f31db40b106cc0f7a51f5daf40a7fdYorke Lee                    offset--;
31553f35c7c31f31db40b106cc0f7a51f5daf40a7fdYorke Lee                }
31653f35c7c31f31db40b106cc0f7a51f5daf40a7fdYorke Lee                if (offset == -1) {
31760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return IGNORE_ITEM_VIEW_TYPE;
31853f35c7c31f31db40b106cc0f7a51f5daf40a7fdYorke Lee                } else {
31953f35c7c31f31db40b106cc0f7a51f5daf40a7fdYorke Lee                    return getItemViewType(i, offset);
32060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
32160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
32260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
32360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
32460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
32560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        throw new ArrayIndexOutOfBoundsException(position);
32660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
32760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
32860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public View getView(int position, View convertView, ViewGroup parent) {
32960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
33060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
3319a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (int i = 0, n = mPartitions.size(); i < n; i++) {
3329a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + mPartitions.get(i).count;
33360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
33460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
3359a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartitions.get(i).hasHeader) {
33660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    offset--;
33760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
33860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                View view;
33960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                if (offset == -1) {
3409a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                    view = getHeaderView(i, mPartitions.get(i).cursor, convertView, parent);
34160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                } else {
3429a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                    if (!mPartitions.get(i).cursor.moveToPosition(offset)) {
34360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                        throw new IllegalStateException("Couldn't move cursor to position "
34460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                                + offset);
34560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    }
3469a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                    view = getView(i, mPartitions.get(i).cursor, offset, convertView, parent);
34760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
34860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                if (view == null) {
34960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    throw new NullPointerException("View should not be null, partition: " + i
35060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                            + " position: " + offset);
35160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
35260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                return view;
35360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
35460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
35560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
35660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
35760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        throw new ArrayIndexOutOfBoundsException(position);
35860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
35960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
36060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
36160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the header view for the specified partition, creating one if needed.
36260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
36360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected View getHeaderView(int partition, Cursor cursor, View convertView,
36460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            ViewGroup parent) {
36560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        View view = convertView != null
36660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                ? convertView
36760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                : newHeaderView(mContext, partition, cursor, parent);
36860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        bindHeaderView(view, partition, cursor);
36960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return view;
37060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
37160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
37260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
37360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Creates the header view for the specified partition.
37460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
37560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected View newHeaderView(Context context, int partition, Cursor cursor,
37660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            ViewGroup parent) {
37760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return null;
37860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
37960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
38060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
38160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Binds the header view for the specified partition.
38260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
38360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected void bindHeaderView(View view, int partition, Cursor cursor) {
38460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
38560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
38660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
38760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns an item view for the specified partition, creating one if needed.
38860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
38960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected View getView(int partition, Cursor cursor, int position, View convertView,
39060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            ViewGroup parent) {
39160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        View view;
39260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        if (convertView != null) {
39360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            view = convertView;
39460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        } else {
39560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            view = newView(mContext, partition, cursor, position, parent);
39660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
39760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        bindView(view, partition, cursor, position);
39860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return view;
39960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
40060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
40160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
40260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Creates an item view for the specified partition and position. Position
40360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * corresponds directly to the current cursor position.
40460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
40560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected abstract View newView(Context context, int partition, Cursor cursor, int position,
40660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            ViewGroup parent);
40760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
40860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
40960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Binds an item view for the specified partition and position. Position
41060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * corresponds directly to the current cursor position.
41160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
41260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected abstract void bindView(View v, int partition, Cursor cursor, int position);
41360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
41460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
41560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns a pre-positioned cursor for the specified list position.
41660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
41760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public Object getItem(int position) {
41860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
41960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
4209a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition mPartition : mPartitions) {
4219a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + mPartition.count;
42260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
42360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
4249a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartition.hasHeader) {
42560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    offset--;
42660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
42760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                if (offset == -1) {
42860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return null;
42960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
4309a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                Cursor cursor = mPartition.cursor;
43160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                cursor.moveToPosition(offset);
43260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                return cursor;
43360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
43460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
43560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
43660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
43760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return null;
43860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
43960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
44060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
44160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns the item ID for the specified list position.
44260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
44360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public long getItemId(int position) {
44460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
44560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
4469a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition mPartition : mPartitions) {
4479a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + mPartition.count;
44860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
44960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
4509a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartition.hasHeader) {
45160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    offset--;
45260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
45360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                if (offset == -1) {
45460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return 0;
45560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
4569a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartition.idColumnIndex == -1) {
45760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return 0;
45860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
45960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
4609a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                Cursor cursor = mPartition.cursor;
46160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                if (cursor == null || cursor.isClosed() || !cursor.moveToPosition(offset)) {
46260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return 0;
46360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
4649a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                return cursor.getLong(mPartition.idColumnIndex);
46560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
46660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
46760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
46860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
46960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return 0;
47060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
47160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
47260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
47360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns false if any partition has a header.
47460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
47560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    @Override
47660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public boolean areAllItemsEnabled() {
4779a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (Partition mPartition : mPartitions) {
4789a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            if (mPartition.hasHeader) {
47960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                return false;
48060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
48160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
48260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return true;
48360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
48460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
48560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
48660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns true for all items except headers.
48760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
48860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    @Override
48960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    public boolean isEnabled(int position) {
49060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        ensureCacheValid();
49160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        int start = 0;
4929a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert        for (int i = 0, n = mPartitions.size(); i < n; i++) {
4939a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert            int end = start + mPartitions.get(i).count;
49460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            if (position >= start && position < end) {
49560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                int offset = position - start;
4969a4f02a8eaf7eb3991900231dbea250e4fb34553Alon Albert                if (mPartitions.get(i).hasHeader && offset == 0) {
49760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return false;
49860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                } else {
49960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                    return isEnabled(i, offset);
50060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov                }
50160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            }
50260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov            start = end;
50360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        }
50460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
50560ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return false;
50660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
50760ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov
50860ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    /**
50960ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * Returns true if the item at the specified offset of the specified
51060ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     * partition is selectable and clickable.
51160ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov     */
51260ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    protected boolean isEnabled(int partition, int position) {
51360ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov        return true;
51460ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov    }
51555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov
51655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    /**
51755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov     * Enable or disable data change notifications.  It may be a good idea to
51855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov     * disable notifications before making changes to several partitions at once.
51955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov     */
52055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    public void setNotificationsEnabled(boolean flag) {
5217c76d5f2cd2cc35e7c4f33264d5f281c96351377Gilles Debunne        mNotificationsEnabled = flag;
5227c76d5f2cd2cc35e7c4f33264d5f281c96351377Gilles Debunne        if (flag && mNotificationNeeded) {
52355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            notifyDataSetChanged();
52455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        }
52555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    }
52655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov
52755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    @Override
52855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    public void notifyDataSetChanged() {
52955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        if (mNotificationsEnabled) {
53055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            mNotificationNeeded = false;
53155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            super.notifyDataSetChanged();
53255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        } else {
53355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            mNotificationNeeded = true;
53455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        }
53555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov    }
53660ae52719e0567fa5b1860df19807716951eca50Dmitri Plotnikov}
537