1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-30 13:12:25 -05:00

Do sorting in MergeCursor when merging the query results

Disabled "sort by sender" for now because the database can't sort by
contact names from the contacts database. We probably have to
special-case that and do in-memory sorting.
This commit is contained in:
cketti 2012-10-27 02:15:30 +02:00
parent d74ca8c8ce
commit faa666394c
6 changed files with 270 additions and 155 deletions

View File

@ -29,9 +29,11 @@
<item <item
android:id="@+id/set_sort_subject" android:id="@+id/set_sort_subject"
android:title="@string/sort_by_subject"/> android:title="@string/sort_by_subject"/>
<!--
<item <item
android:id="@+id/set_sort_sender" android:id="@+id/set_sort_sender"
android:title="@string/sort_by_sender"/> android:title="@string/sort_by_sender"/>
-->
<item <item
android:id="@+id/set_sort_flag" android:id="@+id/set_sort_flag"
android:title="@string/sort_by_flag"/> android:title="@string/sort_by_flag"/>

View File

@ -94,7 +94,7 @@ public class Account implements BaseAccount {
SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false), SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false),
SORT_ARRIVAL(R.string.sort_earliest_first, R.string.sort_latest_first, false), SORT_ARRIVAL(R.string.sort_earliest_first, R.string.sort_latest_first, false),
SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true), SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true),
SORT_SENDER(R.string.sort_sender_alpha, R.string.sort_sender_re_alpha, true), // SORT_SENDER(R.string.sort_sender_alpha, R.string.sort_sender_re_alpha, true),
SORT_UNREAD(R.string.sort_unread_first, R.string.sort_unread_last, true), SORT_UNREAD(R.string.sort_unread_first, R.string.sort_unread_last, true),
SORT_FLAGGED(R.string.sort_flagged_first, R.string.sort_flagged_last, true), SORT_FLAGGED(R.string.sort_flagged_first, R.string.sort_flagged_last, true),
SORT_ATTACHMENT(R.string.sort_attach_first, R.string.sort_unattached_first, true); SORT_ATTACHMENT(R.string.sort_attach_first, R.string.sort_unattached_first, true);

View File

@ -374,10 +374,10 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
mMessageListFragment.changeSort(SortType.SORT_SUBJECT); mMessageListFragment.changeSort(SortType.SORT_SUBJECT);
return true; return true;
} }
case R.id.set_sort_sender: { // case R.id.set_sort_sender: {
mMessageListFragment.changeSort(SortType.SORT_SENDER); // mMessageListFragment.changeSort(SortType.SORT_SENDER);
return true; // return true;
} // }
case R.id.set_sort_flag: { case R.id.set_sort_flag: {
mMessageListFragment.changeSort(SortType.SORT_FLAGGED); mMessageListFragment.changeSort(SortType.SORT_FLAGGED);
return true; return true;

View File

@ -7,8 +7,6 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -69,7 +67,6 @@ import com.fsck.k9.R;
import com.fsck.k9.activity.ActivityListener; import com.fsck.k9.activity.ActivityListener;
import com.fsck.k9.activity.ChooseFolder; import com.fsck.k9.activity.ChooseFolder;
import com.fsck.k9.activity.FolderInfoHolder; import com.fsck.k9.activity.FolderInfoHolder;
import com.fsck.k9.activity.MessageInfoHolder;
import com.fsck.k9.activity.MessageReference; import com.fsck.k9.activity.MessageReference;
import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.fragment.ConfirmationDialogFragment; import com.fsck.k9.fragment.ConfirmationDialogFragment;
@ -77,7 +74,6 @@ import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmen
import com.fsck.k9.helper.MessageHelper; import com.fsck.k9.helper.MessageHelper;
import com.fsck.k9.helper.MergeCursorWithUniqueId; import com.fsck.k9.helper.MergeCursorWithUniqueId;
import com.fsck.k9.helper.StringUtils; import com.fsck.k9.helper.StringUtils;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Folder;
@ -173,7 +169,6 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
// arg1 & 2 are mixed up, this is done on purpose // arg1 & 2 are mixed up, this is done on purpose
return mDelegate.compare(object2, object1); return mDelegate.compare(object2, object1);
} }
} }
/** /**
@ -182,7 +177,6 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
* @param <T> * @param <T>
*/ */
public static class ComparatorChain<T> implements Comparator<T> { public static class ComparatorChain<T> implements Comparator<T> {
private List<Comparator<T>> mChain; private List<Comparator<T>> mChain;
/** /**
@ -204,89 +198,93 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
} }
return result; return result;
} }
} }
public static class AttachmentComparator implements Comparator<MessageInfoHolder> { public static class ReverseIdComparator implements Comparator<Cursor> {
private int mIdColumn = -1;
@Override @Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { public int compare(Cursor cursor1, Cursor cursor2) {
return (object1.message.hasAttachments() ? 0 : 1) - (object2.message.hasAttachments() ? 0 : 1); if (mIdColumn == -1) {
mIdColumn = cursor1.getColumnIndex("_id");
}
long o1Id = cursor1.getLong(mIdColumn);
long o2Id = cursor2.getLong(mIdColumn);
return (o1Id > o2Id) ? -1 : 1;
}
} }
} public static class AttachmentComparator implements Comparator<Cursor> {
public static class FlaggedComparator implements Comparator<MessageInfoHolder> {
@Override @Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { public int compare(Cursor cursor1, Cursor cursor2) {
return (object1.flagged ? 0 : 1) - (object2.flagged ? 0 : 1); int o1HasAttachment = (cursor1.getInt(ATTACHMENT_COUNT_COLUMN) > 0) ? 0 : 1;
int o2HasAttachment = (cursor2.getInt(ATTACHMENT_COUNT_COLUMN) > 0) ? 0 : 1;
return o1HasAttachment - o2HasAttachment;
}
} }
} public static class FlaggedComparator implements Comparator<Cursor> {
public static class UnreadComparator implements Comparator<MessageInfoHolder> {
@Override @Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { public int compare(Cursor cursor1, Cursor cursor2) {
return (object1.read ? 1 : 0) - (object2.read ? 1 : 0); int o1IsFlagged = (cursor1.getString(FLAGS_COLUMN).contains("FLAGGED")) ? 0 : 1;
int o2IsFlagged = (cursor2.getString(FLAGS_COLUMN).contains("FLAGGED")) ? 0 : 1;
return o1IsFlagged - o2IsFlagged;
}
} }
} public static class UnreadComparator implements Comparator<Cursor> {
public static class SenderComparator implements Comparator<MessageInfoHolder> {
@Override @Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { public int compare(Cursor cursor1, Cursor cursor2) {
if (object1.compareCounterparty == null) { int o1IsUnread = (cursor1.getString(FLAGS_COLUMN).contains("SEEN")) ? 1 : 0;
return (object2.compareCounterparty == null ? 0 : 1); int o2IsUnread = (cursor2.getString(FLAGS_COLUMN).contains("SEEN")) ? 1 : 0;
} else if (object2.compareCounterparty == null) { return o1IsUnread - o2IsUnread;
}
}
public static class DateComparator implements Comparator<Cursor> {
@Override
public int compare(Cursor cursor1, Cursor cursor2) {
long o1Date = cursor1.getLong(DATE_COLUMN);
long o2Date = cursor2.getLong(DATE_COLUMN);
if (o1Date < o2Date) {
return -1;
} else if (o1Date == o2Date) {
return 0;
} else {
return 1;
}
}
}
public static class ArrivalComparator implements Comparator<Cursor> {
@Override
public int compare(Cursor cursor1, Cursor cursor2) {
long o1Date = cursor1.getLong(INTERNAL_DATE_COLUMN);
long o2Date = cursor2.getLong(INTERNAL_DATE_COLUMN);
if (o1Date == o2Date) {
return 0;
} else if (o1Date < o2Date) {
return -1; return -1;
} else { } else {
return object1.compareCounterparty.toLowerCase().compareTo(object2.compareCounterparty.toLowerCase()); return 1;
}
} }
} }
} public static class SubjectComparator implements Comparator<Cursor> {
public static class DateComparator implements Comparator<MessageInfoHolder> {
@Override @Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) { public int compare(Cursor cursor1, Cursor cursor2) {
if (object1.compareDate == null) { String subject1 = cursor1.getString(SUBJECT_COLUMN);
return (object2.compareDate == null ? 0 : 1); String subject2 = cursor2.getString(SUBJECT_COLUMN);
} else if (object2.compareDate == null) {
return -1;
} else {
return object1.compareDate.compareTo(object2.compareDate);
}
}
return subject1.compareToIgnoreCase(subject2);
} }
public static class ArrivalComparator implements Comparator<MessageInfoHolder> {
@Override
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
return object1.compareArrival.compareTo(object2.compareArrival);
}
}
public static class SubjectComparator implements Comparator<MessageInfoHolder> {
@Override
public int compare(MessageInfoHolder arg0, MessageInfoHolder arg1) {
// XXX doesn't respect the Comparator contract since it alters the compared object
if (arg0.compareSubject == null) {
arg0.compareSubject = Utility.stripSubject(arg0.message.getSubject());
}
if (arg1.compareSubject == null) {
arg1.compareSubject = Utility.stripSubject(arg1.message.getSubject());
}
return arg0.compareSubject.compareToIgnoreCase(arg1.compareSubject);
}
} }
@ -301,17 +299,17 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
/** /**
* Maps a {@link SortType} to a {@link Comparator} implementation. * Maps a {@link SortType} to a {@link Comparator} implementation.
*/ */
private static final Map<SortType, Comparator<MessageInfoHolder>> SORT_COMPARATORS; private static final Map<SortType, Comparator<Cursor>> SORT_COMPARATORS;
static { static {
// fill the mapping at class time loading // fill the mapping at class time loading
final Map<SortType, Comparator<MessageInfoHolder>> map = new EnumMap<SortType, Comparator<MessageInfoHolder>>(SortType.class); final Map<SortType, Comparator<Cursor>> map =
new EnumMap<SortType, Comparator<Cursor>>(SortType.class);
map.put(SortType.SORT_ATTACHMENT, new AttachmentComparator()); map.put(SortType.SORT_ATTACHMENT, new AttachmentComparator());
map.put(SortType.SORT_DATE, new DateComparator()); map.put(SortType.SORT_DATE, new DateComparator());
map.put(SortType.SORT_ARRIVAL, new ArrivalComparator()); map.put(SortType.SORT_ARRIVAL, new ArrivalComparator());
map.put(SortType.SORT_FLAGGED, new FlaggedComparator()); map.put(SortType.SORT_FLAGGED, new FlaggedComparator());
map.put(SortType.SORT_SENDER, new SenderComparator());
map.put(SortType.SORT_SUBJECT, new SubjectComparator()); map.put(SortType.SORT_SUBJECT, new SubjectComparator());
map.put(SortType.SORT_UNREAD, new UnreadComparator()); map.put(SortType.SORT_UNREAD, new UnreadComparator());
@ -471,35 +469,33 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
* @return The comparator to use to display messages in an ordered * @return The comparator to use to display messages in an ordered
* fashion. Never <code>null</code>. * fashion. Never <code>null</code>.
*/ */
protected Comparator<MessageInfoHolder> getComparator() { protected Comparator<Cursor> getComparator() {
final List<Comparator<MessageInfoHolder>> chain = new ArrayList<Comparator<MessageInfoHolder>>(2 /* we add 2 comparators at most */); final List<Comparator<Cursor>> chain =
new ArrayList<Comparator<Cursor>>(3 /* we add 3 comparators at most */);
{ // Add the specified comparator
// add the specified comparator final Comparator<Cursor> comparator = SORT_COMPARATORS.get(mSortType);
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(mSortType);
if (mSortAscending) { if (mSortAscending) {
chain.add(comparator); chain.add(comparator);
} else { } else {
chain.add(new ReverseComparator<MessageInfoHolder>(comparator)); chain.add(new ReverseComparator<Cursor>(comparator));
}
} }
{ // Add the date comparator if not already specified
// add the date comparator if not already specified
if (mSortType != SortType.SORT_DATE && mSortType != SortType.SORT_ARRIVAL) { if (mSortType != SortType.SORT_DATE && mSortType != SortType.SORT_ARRIVAL) {
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(SortType.SORT_DATE); final Comparator<Cursor> dateComparator = SORT_COMPARATORS.get(SortType.SORT_DATE);
if (mSortDateAscending) { if (mSortDateAscending) {
chain.add(comparator); chain.add(dateComparator);
} else { } else {
chain.add(new ReverseComparator<MessageInfoHolder>(comparator)); chain.add(new ReverseComparator<Cursor>(dateComparator));
}
} }
} }
// build the comparator chain // Add the id comparator
final Comparator<MessageInfoHolder> chainComparator = new ComparatorChain<MessageInfoHolder>(chain); chain.add(new ReverseIdComparator());
return chainComparator; // Build the comparator chain
return new ComparatorChain<Cursor>(chain);
} }
private void folderLoading(String folder, boolean loading) { private void folderLoading(String folder, boolean loading) {
@ -699,6 +695,9 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
initializeMessageList(); initializeMessageList();
// This needs to be done before initializing the cursor loader below
initializeSortSettings();
LoaderManager loaderManager = getLoaderManager(); LoaderManager loaderManager = getLoaderManager();
int len = mAccountUuids.length; int len = mAccountUuids.length;
mCursors = new Cursor[len]; mCursors = new Cursor[len];
@ -707,6 +706,18 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
} }
} }
private void initializeSortSettings() {
if (mSingleAccountMode) {
mSortType = mAccount.getSortType();
mSortAscending = mAccount.isSortAscending(mSortType);
mSortDateAscending = mAccount.isSortAscending(SortType.SORT_DATE);
} else {
mSortType = K9.getSortType();
mSortAscending = K9.isSortAscending(mSortType);
mSortDateAscending = K9.isSortAscending(SortType.SORT_DATE);
}
}
private void decodeArguments() { private void decodeArguments() {
Bundle args = getArguments(); Bundle args = getArguments();
@ -781,11 +792,24 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
} }
private String getFolderNameById(Account account, long folderId) { private String getFolderNameById(Account account, long folderId) {
try {
Folder folder = getFolderById(account, folderId);
if (folder != null) {
return folder.getName();
}
} catch (Exception e) {
Log.e(K9.LOG_TAG, "getFolderNameById() failed.", e);
}
return null;
}
private Folder getFolderById(Account account, long folderId) {
try { try {
LocalStore localStore = account.getLocalStore(); LocalStore localStore = account.getLocalStore();
LocalFolder localFolder = localStore.getFolderById(folderId); LocalFolder localFolder = localStore.getFolderById(folderId);
localFolder.open(OpenMode.READ_ONLY); localFolder.open(OpenMode.READ_ONLY);
return localFolder.getName(); return localFolder;
} catch (Exception e) { } catch (Exception e) {
Log.e(K9.LOG_TAG, "getFolderNameById() failed.", e); Log.e(K9.LOG_TAG, "getFolderNameById() failed.", e);
return null; return null;
@ -879,17 +903,10 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
Account[] accountsWithNotification; Account[] accountsWithNotification;
Account account = mAccount; Account account = mAccount;
if (account != null) { if (account != null) {
accountsWithNotification = new Account[] { account }; accountsWithNotification = new Account[] { account };
mSortType = account.getSortType();
mSortAscending = account.isSortAscending(mSortType);
mSortDateAscending = account.isSortAscending(SortType.SORT_DATE);
} else { } else {
accountsWithNotification = mPreferences.getAccounts(); accountsWithNotification = mPreferences.getAccounts();
mSortType = K9.getSortType();
mSortAscending = K9.isSortAscending(mSortType);
mSortDateAscending = K9.isSortAscending(SortType.SORT_DATE);
} }
for (Account accountWithNotification : accountsWithNotification) { for (Account accountWithNotification : accountsWithNotification) {
@ -1145,10 +1162,10 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
changeSort(SortType.SORT_SUBJECT); changeSort(SortType.SORT_SUBJECT);
return true; return true;
} }
case R.id.set_sort_sender: { // case R.id.set_sort_sender: {
changeSort(SortType.SORT_SENDER); // changeSort(SortType.SORT_SENDER);
return true; // return true;
} // }
case R.id.set_sort_flag: { case R.id.set_sort_flag: {
changeSort(SortType.SORT_FLAGGED); changeSort(SortType.SORT_FLAGGED);
return true; return true;
@ -2496,8 +2513,9 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
Cursor cursor = (Cursor) mAdapter.getItem(adapterPosition); Cursor cursor = (Cursor) mAdapter.getItem(adapterPosition);
String uid = cursor.getString(UID_COLUMN); String uid = cursor.getString(UID_COLUMN);
//TODO: get account and folder from cursor Account account = getAccountFromCursor(cursor);
Folder folder = mCurrentFolder.folder; long folderId = cursor.getLong(FOLDER_ID_COLUMN);
Folder folder = getFolderById(account, folderId);
try { try {
return folder.getMessage(uid); return folder.getMessage(uid);
@ -2668,13 +2686,13 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
sortColumn = "(" + MessageColumns.FLAGS + " NOT LIKE '%FLAGGED%')"; sortColumn = "(" + MessageColumns.FLAGS + " NOT LIKE '%FLAGGED%')";
break; break;
} }
case SORT_SENDER: { // case SORT_SENDER: {
//FIXME // //FIXME
sortColumn = MessageColumns.SENDER_LIST; // sortColumn = MessageColumns.SENDER_LIST;
break; // break;
} // }
case SORT_SUBJECT: { case SORT_SUBJECT: {
sortColumn = MessageColumns.SUBJECT; sortColumn = MessageColumns.SUBJECT + " COLLATE NOCASE";
break; break;
} }
case SORT_UNREAD: { case SORT_UNREAD: {
@ -2687,14 +2705,12 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
} }
} }
String sortDirection; String sortDirection = (mSortAscending) ? " ASC" : " DESC";
String secondarySort; String secondarySort;
if (mSortType == SortType.SORT_DATE) { if (mSortType == SortType.SORT_DATE || mSortType == SortType.SORT_ARRIVAL) {
sortDirection = (mSortDateAscending) ? " ASC" : " DESC";
secondarySort = ""; secondarySort = "";
} else { } else {
sortDirection = (mSortAscending) ? " ASC" : " DESC"; secondarySort = MessageColumns.DATE + ((mSortDateAscending) ? " ASC, " : " DESC, ");
secondarySort = MessageColumns.DATE + " DESC, ";
} }
String sortOrder = sortColumn + sortDirection + ", " + secondarySort + String sortOrder = sortColumn + sortDirection + ", " + secondarySort +
@ -2759,9 +2775,13 @@ public class MessageListFragment extends SherlockFragment implements OnItemClick
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
Cursor cursor;
if (mCursors.length > 1) {
mCursors[loader.getId()] = data; mCursors[loader.getId()] = data;
cursor = new MergeCursorWithUniqueId(mCursors, getComparator());
MergeCursorWithUniqueId cursor = new MergeCursorWithUniqueId(mCursors); } else {
cursor = data;
}
mSelected = new SparseBooleanArray(cursor.getCount()); mSelected = new SparseBooleanArray(cursor.getCount());
//TODO: use the (stable) IDs as index and reuse the old mSelected //TODO: use the (stable) IDs as index and reuse the old mSelected

View File

@ -17,6 +17,8 @@
package com.fsck.k9.helper; package com.fsck.k9.helper;
import java.util.Comparator;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.database.CharArrayBuffer; import android.database.CharArrayBuffer;
@ -48,30 +50,53 @@ public class MergeCursor implements Cursor {
*/ */
protected int mActiveCursorIndex; protected int mActiveCursorIndex;
/**
* The cursor's current position.
*/
protected int mPosition; protected int mPosition;
/** /**
* Used to cache the value of {@link #getCount()} * Used to cache the value of {@link #getCount()}.
*/ */
private int mCount = -1; private int mCount = -1;
/**
* The comparator that is used to decide how the individual cursors are merged.
*/
private final Comparator<Cursor> mComparator;
/** /**
* Constructor * Constructor
* *
* @param cursors * @param cursors
* The list of cursors this {@code MultiCursor} should combine. * The list of cursors this {@code MultiCursor} should combine.
* @param comparator
* A comparator that is used to decide in what order the individual cursors are merged.
*/ */
public MergeCursor(Cursor[] cursors) { public MergeCursor(Cursor[] cursors, Comparator<Cursor> comparator) {
mCursors = cursors.clone(); mCursors = cursors.clone();
mComparator = comparator;
resetCursors();
}
private void resetCursors() {
mActiveCursorIndex = -1;
mActiveCursor = null;
mPosition = -1;
for (int i = 0, len = mCursors.length; i < len; i++) { for (int i = 0, len = mCursors.length; i < len; i++) {
if (mCursors[i] != null) { Cursor cursor = mCursors[i];
if (cursor != null) {
cursor.moveToPosition(-1);
if (mActiveCursor == null) {
mActiveCursorIndex = i; mActiveCursorIndex = i;
mActiveCursor = mCursors[mActiveCursorIndex]; mActiveCursor = mCursors[mActiveCursorIndex];
} }
} }
mPosition = -1; }
} }
@Override @Override
@ -255,7 +280,50 @@ public class MergeCursor implements Cursor {
@Override @Override
public boolean moveToNext() { public boolean moveToNext() {
return moveToPosition(mPosition + 1); int count = getCount();
if (mPosition == count) {
return false;
}
if (mPosition == count - 1) {
mActiveCursor.moveToNext();
mPosition++;
return false;
}
int smallest = -1;
for (int i = 0, len = mCursors.length; i < len; i++) {
if (mCursors[i] == null || mCursors[i].isLast()) {
continue;
}
if (smallest == -1) {
smallest = i;
mCursors[smallest].moveToNext();
continue;
}
Cursor left = mCursors[smallest];
Cursor right = mCursors[i];
right.moveToNext();
int result = mComparator.compare(left, right);
if (result > 0) {
smallest = i;
left.moveToPrevious();
} else {
right.moveToPrevious();
}
}
mPosition++;
if (smallest != -1) {
mActiveCursorIndex = smallest;
mActiveCursor = mCursors[mActiveCursorIndex];
}
return true;
} }
@Override @Override
@ -278,40 +346,63 @@ public class MergeCursor implements Cursor {
return true; return true;
} }
/* Find the right cursor */ if (position > mPosition) {
mActiveCursor = null; for (int i = 0, end = position - mPosition; i < end; i++) {
mActiveCursorIndex = -1; if (!moveToNext()) {
mPosition = -1;
int cursorStartPos = 0;
for (int i = 0, len = mCursors.length; i < len; i++) {
if (mCursors[i] == null) {
continue;
}
if (position < (cursorStartPos + mCursors[i].getCount())) {
mActiveCursorIndex = i;
mActiveCursor = mCursors[mActiveCursorIndex];
break;
}
cursorStartPos += mCursors[i].getCount();
}
/* Move it to the right position */
if (mActiveCursor != null) {
boolean success = mActiveCursor.moveToPosition(position - cursorStartPos);
mPosition = (success) ? position : -1;
return success;
}
return false; return false;
} }
}
} else {
for (int i = 0, end = mPosition - position; i < end; i++) {
if (!moveToPrevious()) {
return false;
}
}
}
return true;
}
@Override @Override
public boolean moveToPrevious() { public boolean moveToPrevious() {
return moveToPosition(mPosition - 1); if (mPosition < 0) {
return false;
}
mActiveCursor.moveToPrevious();
if (mPosition == 0) {
mPosition = -1;
return false;
}
int greatest = -1;
for (int i = 0, len = mCursors.length; i < len; i++) {
if (mCursors[i] == null || mCursors[i].isBeforeFirst()) {
continue;
}
if (greatest == -1) {
greatest = i;
continue;
}
Cursor left = mCursors[greatest];
Cursor right = mCursors[i];
int result = mComparator.compare(left, right);
if (result <= 0) {
greatest = i;
}
}
mPosition--;
if (greatest != -1) {
mActiveCursorIndex = greatest;
mActiveCursor = mCursors[mActiveCursorIndex];
}
return true;
} }
@Override @Override

View File

@ -1,5 +1,7 @@
package com.fsck.k9.helper; package com.fsck.k9.helper;
import java.util.Comparator;
import android.database.Cursor; import android.database.Cursor;
@ -12,8 +14,8 @@ public class MergeCursorWithUniqueId extends MergeCursor {
private int mIdColumnIndex = -1; private int mIdColumnIndex = -1;
public MergeCursorWithUniqueId(Cursor[] cursors) { public MergeCursorWithUniqueId(Cursor[] cursors, Comparator<Cursor> comparator) {
super(cursors); super(cursors, comparator);
if (cursors.length > MAX_CURSORS) { if (cursors.length > MAX_CURSORS) {
throw new IllegalArgumentException("This class only supports up to " + throw new IllegalArgumentException("This class only supports up to " +