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.database;
18
19/**
20 * A convience class that lets you present an array of Cursors as a single linear Cursor.
21 * The schema of the cursors presented is entirely up to the creator of the MergeCursor, and
22 * may be different if that is desired. Calls to getColumns, getColumnIndex, etc will return the
23 * value for the row that the MergeCursor is currently pointing at.
24 */
25public class MergeCursor extends AbstractCursor
26{
27    private DataSetObserver mObserver = new DataSetObserver() {
28
29        @Override
30        public void onChanged() {
31            // Reset our position so the optimizations in move-related code
32            // don't screw us over
33            mPos = -1;
34        }
35
36        @Override
37        public void onInvalidated() {
38            mPos = -1;
39        }
40    };
41
42    public MergeCursor(Cursor[] cursors)
43    {
44        mCursors = cursors;
45        mCursor = cursors[0];
46
47        for (int i = 0; i < mCursors.length; i++) {
48            if (mCursors[i] == null) continue;
49
50            mCursors[i].registerDataSetObserver(mObserver);
51        }
52    }
53
54    @Override
55    public int getCount()
56    {
57        int count = 0;
58        int length = mCursors.length;
59        for (int i = 0 ; i < length ; i++) {
60            if (mCursors[i] != null) {
61                count += mCursors[i].getCount();
62            }
63        }
64        return count;
65    }
66
67    @Override
68    public boolean onMove(int oldPosition, int newPosition)
69    {
70        /* Find the right cursor */
71        mCursor = null;
72        int cursorStartPos = 0;
73        int length = mCursors.length;
74        for (int i = 0 ; i < length; i++) {
75            if (mCursors[i] == null) {
76                continue;
77            }
78
79            if (newPosition < (cursorStartPos + mCursors[i].getCount())) {
80                mCursor = mCursors[i];
81                break;
82            }
83
84            cursorStartPos += mCursors[i].getCount();
85        }
86
87        /* Move it to the right position */
88        if (mCursor != null) {
89            boolean ret = mCursor.moveToPosition(newPosition - cursorStartPos);
90            return ret;
91        }
92        return false;
93    }
94
95    @Override
96    public String getString(int column)
97    {
98        return mCursor.getString(column);
99    }
100
101    @Override
102    public short getShort(int column)
103    {
104        return mCursor.getShort(column);
105    }
106
107    @Override
108    public int getInt(int column)
109    {
110        return mCursor.getInt(column);
111    }
112
113    @Override
114    public long getLong(int column)
115    {
116        return mCursor.getLong(column);
117    }
118
119    @Override
120    public float getFloat(int column)
121    {
122        return mCursor.getFloat(column);
123    }
124
125    @Override
126    public double getDouble(int column)
127    {
128        return mCursor.getDouble(column);
129    }
130
131    @Override
132    public int getType(int column) {
133        return mCursor.getType(column);
134    }
135
136    @Override
137    public boolean isNull(int column)
138    {
139        return mCursor.isNull(column);
140    }
141
142    @Override
143    public byte[] getBlob(int column)
144    {
145        return mCursor.getBlob(column);
146    }
147
148    @Override
149    public String[] getColumnNames()
150    {
151        if (mCursor != null) {
152            return mCursor.getColumnNames();
153        } else {
154            return new String[0];
155        }
156    }
157
158    @Override
159    public void deactivate()
160    {
161        int length = mCursors.length;
162        for (int i = 0 ; i < length ; i++) {
163            if (mCursors[i] != null) {
164                mCursors[i].deactivate();
165            }
166        }
167        super.deactivate();
168    }
169
170    @Override
171    public void close() {
172        int length = mCursors.length;
173        for (int i = 0 ; i < length ; i++) {
174            if (mCursors[i] == null) continue;
175            mCursors[i].close();
176        }
177        super.close();
178    }
179
180    @Override
181    public void registerContentObserver(ContentObserver observer) {
182        int length = mCursors.length;
183        for (int i = 0 ; i < length ; i++) {
184            if (mCursors[i] != null) {
185                mCursors[i].registerContentObserver(observer);
186            }
187        }
188    }
189    @Override
190    public void unregisterContentObserver(ContentObserver observer) {
191        int length = mCursors.length;
192        for (int i = 0 ; i < length ; i++) {
193            if (mCursors[i] != null) {
194                mCursors[i].unregisterContentObserver(observer);
195            }
196        }
197    }
198
199    @Override
200    public void registerDataSetObserver(DataSetObserver observer) {
201        int length = mCursors.length;
202        for (int i = 0 ; i < length ; i++) {
203            if (mCursors[i] != null) {
204                mCursors[i].registerDataSetObserver(observer);
205            }
206        }
207    }
208
209    @Override
210    public void unregisterDataSetObserver(DataSetObserver observer) {
211        int length = mCursors.length;
212        for (int i = 0 ; i < length ; i++) {
213            if (mCursors[i] != null) {
214                mCursors[i].unregisterDataSetObserver(observer);
215            }
216        }
217    }
218
219    @Override
220    public boolean requery()
221    {
222        int length = mCursors.length;
223        for (int i = 0 ; i < length ; i++) {
224            if (mCursors[i] == null) {
225                continue;
226            }
227
228            if (mCursors[i].requery() == false) {
229                return false;
230            }
231        }
232
233        return true;
234    }
235
236    private Cursor mCursor; // updated in onMove
237    private Cursor[] mCursors;
238}
239