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    /**
96     * @hide
97     * @deprecated
98     */
99    @Override
100    public boolean deleteRow()
101    {
102        return mCursor.deleteRow();
103    }
104
105    /**
106     * @hide
107     * @deprecated
108     */
109    @Override
110    public boolean commitUpdates() {
111        int length = mCursors.length;
112        for (int i = 0 ; i < length ; i++) {
113            if (mCursors[i] != null) {
114                mCursors[i].commitUpdates();
115            }
116        }
117        onChange(true);
118        return true;
119    }
120
121    @Override
122    public String getString(int column)
123    {
124        return mCursor.getString(column);
125    }
126
127    @Override
128    public short getShort(int column)
129    {
130        return mCursor.getShort(column);
131    }
132
133    @Override
134    public int getInt(int column)
135    {
136        return mCursor.getInt(column);
137    }
138
139    @Override
140    public long getLong(int column)
141    {
142        return mCursor.getLong(column);
143    }
144
145    @Override
146    public float getFloat(int column)
147    {
148        return mCursor.getFloat(column);
149    }
150
151    @Override
152    public double getDouble(int column)
153    {
154        return mCursor.getDouble(column);
155    }
156
157    @Override
158    public boolean isNull(int column)
159    {
160        return mCursor.isNull(column);
161    }
162
163    @Override
164    public byte[] getBlob(int column)
165    {
166        return mCursor.getBlob(column);
167    }
168
169    @Override
170    public String[] getColumnNames()
171    {
172        if (mCursor != null) {
173            return mCursor.getColumnNames();
174        } else {
175            return new String[0];
176        }
177    }
178
179    @Override
180    public void deactivate()
181    {
182        int length = mCursors.length;
183        for (int i = 0 ; i < length ; i++) {
184            if (mCursors[i] != null) {
185                mCursors[i].deactivate();
186            }
187        }
188        super.deactivate();
189    }
190
191    @Override
192    public void close() {
193        int length = mCursors.length;
194        for (int i = 0 ; i < length ; i++) {
195            if (mCursors[i] == null) continue;
196            mCursors[i].close();
197        }
198        super.close();
199    }
200
201    @Override
202    public void registerContentObserver(ContentObserver observer) {
203        int length = mCursors.length;
204        for (int i = 0 ; i < length ; i++) {
205            if (mCursors[i] != null) {
206                mCursors[i].registerContentObserver(observer);
207            }
208        }
209    }
210    @Override
211    public void unregisterContentObserver(ContentObserver observer) {
212        int length = mCursors.length;
213        for (int i = 0 ; i < length ; i++) {
214            if (mCursors[i] != null) {
215                mCursors[i].unregisterContentObserver(observer);
216            }
217        }
218    }
219
220    @Override
221    public void registerDataSetObserver(DataSetObserver observer) {
222        int length = mCursors.length;
223        for (int i = 0 ; i < length ; i++) {
224            if (mCursors[i] != null) {
225                mCursors[i].registerDataSetObserver(observer);
226            }
227        }
228    }
229
230    @Override
231    public void unregisterDataSetObserver(DataSetObserver observer) {
232        int length = mCursors.length;
233        for (int i = 0 ; i < length ; i++) {
234            if (mCursors[i] != null) {
235                mCursors[i].unregisterDataSetObserver(observer);
236            }
237        }
238    }
239
240    @Override
241    public boolean requery()
242    {
243        int length = mCursors.length;
244        for (int i = 0 ; i < length ; i++) {
245            if (mCursors[i] == null) {
246                continue;
247            }
248
249            if (mCursors[i].requery() == false) {
250                return false;
251            }
252        }
253
254        return true;
255    }
256
257    private Cursor mCursor; // updated in onMove
258    private Cursor[] mCursors;
259}
260