michael@0: package org.mozilla.gecko.db; michael@0: michael@0: import android.database.Cursor; michael@0: import android.database.CursorWrapper; michael@0: import android.util.SparseArray; michael@0: michael@0: import org.mozilla.gecko.db.BrowserContract.Bookmarks; michael@0: import org.mozilla.gecko.db.BrowserDB.URLColumns; michael@0: michael@0: /** michael@0: * {@TopSitesCursorWrapper} is a cursor wrapper that merges michael@0: * the top and pinned sites cursors into one. It ensures the michael@0: * cursor will contain at least a given minimum number of michael@0: * entries. michael@0: */ michael@0: public class TopSitesCursorWrapper extends CursorWrapper { michael@0: michael@0: private static class PinnedSite { michael@0: public final String title; michael@0: public final String url; michael@0: michael@0: public PinnedSite(String title, String url) { michael@0: this.title = (title == null ? "" : title); michael@0: this.url = (url == null ? "" : url); michael@0: } michael@0: } michael@0: michael@0: // The cursor for the top sites query michael@0: private final Cursor topCursor; michael@0: michael@0: // Associates pinned sites and their respective positions michael@0: private SparseArray pinnedSites; michael@0: michael@0: // Current position of the cursor michael@0: private int currentPosition = -1; michael@0: michael@0: // The size of the cursor wrapper michael@0: private final int count; michael@0: michael@0: public TopSitesCursorWrapper(Cursor pinnedCursor, Cursor topCursor, int minSize) { michael@0: super(topCursor); michael@0: michael@0: setPinnedSites(pinnedCursor); michael@0: this.topCursor = topCursor; michael@0: michael@0: count = Math.max(minSize, pinnedSites.size() + topCursor.getCount()); michael@0: } michael@0: michael@0: public void setPinnedSites(Cursor c) { michael@0: pinnedSites = new SparseArray(); michael@0: michael@0: if (c == null) { michael@0: return; michael@0: } michael@0: michael@0: try { michael@0: if (c.getCount() <= 0) { michael@0: return; michael@0: } michael@0: michael@0: c.moveToPosition(0); michael@0: do { michael@0: final int pos = c.getInt(c.getColumnIndex(Bookmarks.POSITION)); michael@0: final String url = c.getString(c.getColumnIndex(URLColumns.URL)); michael@0: final String title = c.getString(c.getColumnIndex(URLColumns.TITLE)); michael@0: pinnedSites.put(pos, new PinnedSite(title, url)); michael@0: } while (c.moveToNext()); michael@0: } finally { michael@0: c.close(); michael@0: } michael@0: } michael@0: michael@0: public boolean hasPinnedSites() { michael@0: return (pinnedSites != null && pinnedSites.size() > 0); michael@0: } michael@0: michael@0: public PinnedSite getPinnedSite(int position) { michael@0: if (!hasPinnedSites()) { michael@0: return null; michael@0: } michael@0: michael@0: return pinnedSites.get(position); michael@0: } michael@0: michael@0: public boolean isPinned() { michael@0: return (pinnedSites.get(currentPosition) != null); michael@0: } michael@0: michael@0: private int getPinnedBefore(int position) { michael@0: int numFound = 0; michael@0: if (!hasPinnedSites()) { michael@0: return numFound; michael@0: } michael@0: michael@0: for (int i = 0; i < position; i++) { michael@0: if (pinnedSites.get(i) != null) { michael@0: numFound++; michael@0: } michael@0: } michael@0: michael@0: return numFound; michael@0: } michael@0: michael@0: @Override michael@0: public int getPosition() { michael@0: return currentPosition; michael@0: } michael@0: michael@0: @Override michael@0: public int getCount() { michael@0: return count; michael@0: } michael@0: michael@0: @Override michael@0: public boolean isAfterLast() { michael@0: return (currentPosition >= count); michael@0: } michael@0: michael@0: @Override michael@0: public boolean isBeforeFirst() { michael@0: return (currentPosition < 0); michael@0: } michael@0: michael@0: @Override michael@0: public boolean isLast() { michael@0: return (currentPosition == count - 1); michael@0: } michael@0: michael@0: @Override michael@0: public boolean moveToNext() { michael@0: return moveToPosition(currentPosition + 1); michael@0: } michael@0: michael@0: @Override michael@0: public boolean moveToPrevious() { michael@0: return moveToPosition(currentPosition - 1); michael@0: } michael@0: michael@0: @Override michael@0: public boolean move(int offset) { michael@0: return moveToPosition(currentPosition + offset); michael@0: } michael@0: michael@0: @Override michael@0: public boolean moveToFirst() { michael@0: return moveToPosition(0); michael@0: } michael@0: michael@0: @Override michael@0: public boolean moveToLast() { michael@0: return moveToPosition(count - 1); michael@0: } michael@0: michael@0: @Override michael@0: public boolean moveToPosition(int position) { michael@0: currentPosition = position; michael@0: michael@0: // Move the real cursor as if we were stepping through it to this position. michael@0: // Account for pinned sites, and be careful to update its position to the michael@0: // minimum or maximum position, even if we're moving beyond its bounds. michael@0: final int before = getPinnedBefore(position); michael@0: final int p2 = position - before; michael@0: michael@0: if (p2 <= -1) { michael@0: super.moveToPosition(-1); michael@0: } else if (p2 >= topCursor.getCount()) { michael@0: super.moveToPosition(topCursor.getCount()); michael@0: } else { michael@0: super.moveToPosition(p2); michael@0: } michael@0: michael@0: return (!isBeforeFirst() && !isAfterLast()); michael@0: } michael@0: michael@0: @Override michael@0: public long getLong(int columnIndex) { michael@0: if (hasPinnedSites()) { michael@0: final PinnedSite site = getPinnedSite(currentPosition); michael@0: michael@0: if (site != null) { michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: if (!super.isBeforeFirst() && !super.isAfterLast()) { michael@0: return super.getLong(columnIndex); michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: @Override michael@0: public int getInt(int columnIndex) { michael@0: if (hasPinnedSites()) { michael@0: final PinnedSite site = getPinnedSite(currentPosition); michael@0: michael@0: if (site != null) { michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: if (!super.isBeforeFirst() && !super.isAfterLast()) { michael@0: return super.getInt(columnIndex); michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: @Override michael@0: public String getString(int columnIndex) { michael@0: if (hasPinnedSites()) { michael@0: final PinnedSite site = getPinnedSite(currentPosition); michael@0: michael@0: if (site != null) { michael@0: if (columnIndex == topCursor.getColumnIndex(URLColumns.URL)) { michael@0: return site.url; michael@0: } else if (columnIndex == topCursor.getColumnIndex(URLColumns.TITLE)) { michael@0: return site.title; michael@0: } michael@0: michael@0: return ""; michael@0: } michael@0: } michael@0: michael@0: if (!super.isBeforeFirst() && !super.isAfterLast()) { michael@0: return super.getString(columnIndex); michael@0: } michael@0: michael@0: return ""; michael@0: } michael@0: }