# HG changeset patch # User Da Risk # Date 1275420759 -7200 # Node ID 97451b0f4f0922f85427dc3d8f30ae8adcf965da # Parent 5f7bbb0c2731b67bb63d4ad956158011059deaa3 Refactor the ContactList activity. Use an insertion sorted list to manage the sort. diff -r 5f7bbb0c2731 -r 97451b0f4f09 src/com/beem/project/beem/ui/ContactList.java --- a/src/com/beem/project/beem/ui/ContactList.java Mon May 31 00:56:26 2010 +0200 +++ b/src/com/beem/project/beem/ui/ContactList.java Tue Jun 01 21:32:39 2010 +0200 @@ -50,7 +50,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Iterator; import org.jivesoftware.smack.util.StringUtils; @@ -96,6 +95,7 @@ import com.beem.project.beem.ui.dialogs.builders.ResendSubscription; import com.beem.project.beem.utils.BeemBroadcastReceiver; import com.beem.project.beem.utils.Status; +import com.beem.project.beem.utils.SortedList; /** * The contact list activity displays the roster of the user. @@ -107,11 +107,14 @@ SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService")); } - private static final int REQUEST_CODE = 1; private static final String SETTINGS_HIDDEN_CONTACT = "settings_key_hidden_contact"; private static final String TAG = "ContactList"; private final BeemContactList mAdapterContactList = new BeemContactList(); private final List mListGroup = new ArrayList(); + + /** Map containing a list of the different contacts of a given group. + * Each list is a @{link SortedList} so there is no need to sort it again. + * */ private final Map> mContactOnGroup = new HashMap>(); private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick(); private final Handler mHandler = new Handler(); @@ -133,7 +136,6 @@ * Constructor. */ public ContactList() { - } /** @@ -226,7 +228,8 @@ result = true; break; case R.id.contact_list_context_menu_userinfo_subscription: - Dialog subscription = new ResendSubscription(ContactList.this, mXmppFacade, mSelectedContact).create(); + Dialog subscription = new ResendSubscription(ContactList.this, + mXmppFacade, mSelectedContact).create(); subscription.show(); result = true; break; @@ -300,37 +303,17 @@ } /** - * Comparator Contact by status and name. - */ - private static class ComparatorContactListByStatusAndName implements Comparator { - /** - * Constructor. - */ - public ComparatorContactListByStatusAndName() { - } - - @Override - public int compare(T c1, T c2) { - if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) { - return 1; - } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) { - return -1; - } else - return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName()); - } - } - - /** - * Contact List construction. + * Build and display the contact list. + * @param group name of the contact list. */ private void buildContactList(String group) { mListContact = mContactOnGroup.get(group); Log.d(TAG, "buildContactList for group " + group); - sortBeemContactList(); + mAdapterContactList.notifyDataSetChanged(); } /** - * showGroups. + * Show the groups view. */ private void showGroups() { @@ -340,57 +323,21 @@ Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner); g.setOnItemClickListener(new OnItemClickGroupName()); g.setAdapter(mAdapterBanner); - } else + g.setSelection(0); + } else { ((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE); - } - - /** - * Event simple click on item of the contact list. - */ - private class BeemContactListOnClick implements OnItemClickListener { - /** - * Constructor. - */ - public BeemContactListOnClick() { - } - - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(AdapterView arg0, View v, int pos, long lpos) { - Contact c = mListContact.get(pos); - Intent i = new Intent(ContactList.this, Chat.class); - i.setData(c.toUri()); - startActivity(i); + Gallery g = (Gallery) findViewById(R.id.contactlist_banner); + g.setSelection(0); } } /** - * Event simple click on middle groupe name. + * Hide the groups view. */ - private class OnItemClickGroupName implements OnItemClickListener { - - /** - * Constructor. - */ - public OnItemClickGroupName() { - } - - @Override - public void onItemClick(AdapterView arg0, View v, int i, long l) { - String group = mListGroup.get(i); - buildContactList(group); - } - } - - /** - * Sort the contact list. - */ - private void sortBeemContactList() { - Log.d(TAG, "Sort "); - Collections.sort(mListContact, mComparator); - mAdapterContactList.notifyDataSetChanged(); + private void hideGroups() { + View v = findViewById(R.id.contactlist_groupstub); + if (v != null) + v.setVisibility(View.GONE); } /** @@ -404,133 +351,210 @@ } /** - * Refresh the contact list. + * {@inheritDoc} + * Simple stategy to handle the onEntriesAdded event. + * if contact has to be shown : + *
    + *
  • add him to his groups
  • + *
  • add him to the specials groups + *
*/ - private class RunnableChange implements Runnable { - /** - * Constructor. - */ - public RunnableChange() { + @Override + public void onEntriesAdded(final List addresses) throws RemoteException { + final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); + for (String newName : addresses) { + Contact contact = mRoster.getContact(newName); + boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); + List groups = contact.getGroups(); + if (visible) { + for (String group : groups) { + if (!mListGroup.contains(group)) { + mListGroup.add(mListGroup.size() - 1, group); + List tmplist = new SortedList(new LinkedList(), mComparator); + mContactOnGroup.put(group, tmplist); + } + List contactByGroups = mContactOnGroup.get(group); + if (contactByGroups == mListContact) { + updateCurrentList(group, contact); + continue; + } + contactByGroups.add(contact); + } - } - - /** - * {@inheritDoc} - */ - @Override - public void run() { - sortBeemContactList(); - mAdapterContactList.notifyDataSetChanged(); - mAdapterBanner.notifyDataSetChanged(); + // add the contact to all and no groups + addToSpecialList(contact); + } } } /** * {@inheritDoc} + * Simple stategy to handle the onEntriesDeleted event. + *
    + *
  • Remove the contact from all groups
  • + *
*/ @Override - public void onEntriesAdded(List addresses) throws RemoteException { - boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); - for (String newName : addresses) { - Contact c = mRoster.getContact(newName); - if (!hideDisconnected || Status.statusOnline(c.getStatus())) { - mContactOnGroup.get(getString(R.string.contact_list_all_contact)).add(c); - if (c.getGroups().size() == 0) - mContactOnGroup.get(getString(R.string.contact_list_no_group)).add(c); - for (String group : c.getGroups()) { - if (!mListGroup.contains(group)) { - mListGroup.add(mListGroup.size() - 1, group); - List tmplist = new LinkedList(); - mContactOnGroup.put(group, tmplist); - } - mContactOnGroup.get(group).add(c); + public void onEntriesDeleted(final List addresses) throws RemoteException { + Log.d(TAG, "onEntries deleted " + addresses); + for (String cToDelete : addresses) { + Contact contact = new Contact(cToDelete); + for (Map.Entry> entry : mContactOnGroup.entrySet()) { + List contactByGroups = entry.getValue(); + if (contactByGroups == mListContact) { + updateCurrentList(entry.getKey(), contact); + continue; } + contactByGroups.remove(contact); } + cleanBannerGroup(); } - mHandler.post(new RunnableChange()); + + mHandler.post(new Runnable() { + public void run() { + mListContact = mContactOnGroup.get(getString(R.string.contact_list_all_contact)); + mAdapterContactList.notifyDataSetChanged(); + } + }); + } /** * {@inheritDoc} + * Simple stategy to handle the onEntriesUpdated event. + *
    + *
  • Remove the contact from all groups
  • + *
  • if contact has to be shown add it to his groups
  • + *
  • if contact has to be shown add it to the specials groups
  • + *
*/ @Override - public void onEntriesDeleted(List addresses) throws RemoteException { - Log.d(TAG, "onEntries deleted " + addresses); - for (String cToDelete : addresses) { - Contact contact = mRoster.getContact(cToDelete); - for (List contactByGroups : mContactOnGroup.values()) { + public void onEntriesUpdated(final List addresses) throws RemoteException { + final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); + for (String adr : addresses) { + Contact contact = mRoster.getContact(adr); + boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); + List groups = contact.getGroups(); + for (Map.Entry> entry : mContactOnGroup.entrySet()) { + List contactByGroups = entry.getValue(); + if (contactByGroups == mListContact) { + updateCurrentList(entry.getKey(), contact); + continue; + } contactByGroups.remove(contact); + if (visible) { + for (String group : groups) { + if (!mListGroup.contains(group)) { + mListGroup.add(mListGroup.size() - 1, group); + List tmplist = new SortedList( + new LinkedList(), mComparator); + mContactOnGroup.put(group, tmplist); + } + mContactOnGroup.get(group).remove(contact); + } + } + } - cleanBannerGroup(); + + // add the contact to all and no groups + if (visible) { + addToSpecialList(contact); + } } - mListContact = mContactOnGroup.get(getString(R.string.contact_list_all_contact)); - mHandler.post(new RunnableChange()); + cleanBannerGroup(); } /** * {@inheritDoc} + * Simple stategy to handle the onPresenceChanged event. + *
    + *
  • Remove the contact from all groups
  • + *
  • if contact has to be shown add it to his groups
  • + *
  • if contact has to be shown add it to the specials groups
  • + *
*/ @Override - public void onEntriesUpdated(List addresses) throws RemoteException { - boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); - for (String adr : addresses) { - Contact c = mRoster.getContact(adr); - List groups = c.getGroups(); - for (Map.Entry> entry : mContactOnGroup.entrySet()) { - List contactByGroups = entry.getValue(); - contactByGroups.remove(c); + public void onPresenceChanged(PresenceAdapter presence) throws RemoteException { + Log.d(TAG, "presence"); + String from = presence.getFrom(); + final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); + final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from)); + boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus()); + List groups = contact.getGroups(); + for (Map.Entry> entry : mContactOnGroup.entrySet()) { + List contactByGroups = entry.getValue(); + if (contactByGroups == mListContact) { + updateCurrentList(entry.getKey(), contact); + continue; } - if (!hideDisconnected || Status.statusOnline(c.getStatus())) { - mContactOnGroup.get(getString(R.string.contact_list_all_contact)).add(c); - if (c.getGroups().size() == 0) - mContactOnGroup.get(getString(R.string.contact_list_no_group)).add(c); - for (String group : c.getGroups()) { - if (!mListGroup.contains(group)) { - mListGroup.add(mListGroup.size() - 1, group); - List tmplist = new LinkedList(); - mContactOnGroup.put(group, tmplist); - } - mContactOnGroup.get(group).add(c); + contactByGroups.remove(contact); + if (visible) { + if (groups.contains(entry.getKey())) { + contactByGroups.add(contact); } } } - cleanBannerGroup(); - mHandler.post(new RunnableChange()); + if (visible) { + addToSpecialList(contact); + } + } + + /** + * Add a contact to the special list No Group and All contacts. + * The contact will be added if the list is not the current list otherwise + * the list must be modified in a Handler. + * + * @param contact the contact to add. + */ + private void addToSpecialList(Contact contact) { + List groups = contact.getGroups(); + List list = mContactOnGroup.get(getString(R.string.contact_list_all_contact)); + if (list != mListContact) { + list.add(contact); + } + list = mContactOnGroup.get(getString(R.string.contact_list_no_group)); + if (list != mListContact && groups.isEmpty()) { + list.add(contact); + } } - @Override - public void onPresenceChanged(PresenceAdapter presence) throws RemoteException { - String from = presence.getFrom(); - boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); - Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from)); - for (Map.Entry> entry : mContactOnGroup.entrySet()) { - List contactByGroups = entry.getValue(); - if (contactByGroups.contains(contact)) { - contactByGroups.remove(contact); - if (!hideDisconnected || Status.statusOnline(contact.getStatus())) { - contactByGroups.add(contact); + /** + * Update the current list with the status of contact. + * + * @param listName name of the current list + * @param contact contact to update + */ + private void updateCurrentList(String listName, final Contact contact) { + final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); + final List groups = contact.getGroups(); + String noGroup = getString(R.string.contact_list_no_group); + String allGroup = getString(R.string.contact_list_all_contact); + final boolean add = ((!hideDisconnected || Status.statusOnline(contact.getStatus())) && // must show and + ( + (listName.equals(noGroup) && groups.isEmpty()) || // in no group + groups.contains(listName) || // or in current + listName.equals(allGroup) // or in all + )); + mHandler.post(new Runnable() { + public void run() { + mListContact.remove(contact); + if (add) { + mListContact.add(contact); } - } else { - if (Status.statusOnline(contact.getStatus())) { - List groups = contact.getGroups(); - if (groups.contains(entry.getKey())) { - contactByGroups.add(contact); - } - } + mAdapterContactList.notifyDataSetChanged(); } - } - Log.d(TAG, "presence"); - mHandler.post(new RunnableChange()); + }); + } - private void cleanBannerGroup() { - for (Iterator it = mListGroup.iterator(); it.hasNext(); ){ - String group = it.next(); - if (mContactOnGroup.get(group).size() == 0) { - mContactOnGroup.remove(group); - it.remove(); - } - } + /** + * Remove old groups on the banner. + * @throws RemoteException if an error occur when communicating with the service + */ + private void cleanBannerGroup() throws RemoteException { + List rosterGroups = mRoster.getGroupsNames(); + List realGroups = mListGroup.subList(1, mListContact.size() - 1); + realGroups.retainAll(rosterGroups); } } @@ -600,7 +624,8 @@ if (curContact != null) { TextView v = (TextView) view.findViewById(R.id.contactlistpseudo); - LevelListDrawable mStatusDrawable = (LevelListDrawable) getResources().getDrawable(R.drawable.status_icon); + LevelListDrawable mStatusDrawable = (LevelListDrawable) getResources() + .getDrawable(R.drawable.status_icon); mStatusDrawable.setLevel(curContact.getStatus()); v.setCompoundDrawablesWithIntrinsicBounds(mStatusDrawable, null, null, null); v.setText(curContact.getName()); @@ -619,8 +644,10 @@ /** * Constructor. + * @param inflater the inflater use to create the view for the banner + * @param groups list of the differents groups to adapt */ - public BeemBanner(LayoutInflater inflater, List groups) { + public BeemBanner(final LayoutInflater inflater, final List groups) { mGroups = groups; mInflater = inflater; } @@ -668,22 +695,23 @@ try { mRoster = mXmppFacade.getRoster(); if (mRoster != null) { - mRoster.addRosterListener(mBeemRosterListener); List tmpContactList = mRoster.getContactList(); List tmpGroupList = mRoster.getGroupsNames(); Collections.sort(tmpGroupList); - if (mListGroup.size() > 0) - mListGroup.clear(); + mListGroup.clear(); mListGroup.add(getString(R.string.contact_list_all_contact)); mListGroup.addAll(tmpGroupList); mListGroup.add(getString(R.string.contact_list_no_group)); assignContactToGroups(mRoster.getContactList(), tmpGroupList); + makeSortedList(mContactOnGroup); if (!mSettings.getBoolean("settings_key_hide_groups", false)) showGroups(); else hideGroups(); String group = getString(R.string.contact_list_all_contact); buildContactList(group); + mRoster.addRosterListener(mBeemRosterListener); + Log.d(TAG, "add rester listneer"); } } catch (RemoteException e) { e.printStackTrace(); @@ -704,46 +732,116 @@ mContactOnGroup.clear(); mBinded = false; } + + /** + * Assign the differents contact to their groups. + * This methods will fill the mContactOnGroup map. + * + * @param contacts list of contacts + * @param groupNames list of existing groups + */ + private void assignContactToGroups(List contacts, List groupNames) { + boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); + mContactOnGroup.clear(); + List all = new LinkedList(); + List noGroups = new LinkedList(); + for (String group : groupNames) { + mContactOnGroup.put(group, new LinkedList()); + } + for (Contact c : contacts) { + if (hideDisconnected && !Status.statusOnline(c.getStatus())) { + continue; + } + all.add(c); + List groups = c.getGroups(); + if (groups.isEmpty()) + noGroups.add(c); + else { + for (String currentGroup : groups) { + List contactsByGroups = mContactOnGroup.get(currentGroup); + contactsByGroups.add(c); + } + } + } + mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups); + mContactOnGroup.put(getString(R.string.contact_list_all_contact), all); + } + + /** + * Make the List of the map became Insertion sorted list. + * + * @param map the map to convert. + */ + private void makeSortedList(Map> map) { + for (Map.Entry> entry : map.entrySet()) { + List l = entry.getValue(); + entry.setValue(new SortedList(l, mComparator)); + } + } } - @Override - protected void finalize() { - Log.e(TAG, "FINALIZE"); + + + + /** + * Comparator Contact by status and name. + */ + private static class ComparatorContactListByStatusAndName implements Comparator { + /** + * Constructor. + */ + public ComparatorContactListByStatusAndName() { + } + + @Override + public int compare(T c1, T c2) { + if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) { + return 1; + } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) { + return -1; + } else + return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName()); + } } /** - * Hide the groups view. + * Event simple click on item of the contact list. */ - private void hideGroups() { - View v = findViewById(R.id.contactlist_groupstub); - if (v != null) - v.setVisibility(View.GONE); + private class BeemContactListOnClick implements OnItemClickListener { + /** + * Constructor. + */ + public BeemContactListOnClick() { + } + + /** + * {@inheritDoc} + */ + @Override + public void onItemClick(AdapterView arg0, View v, int pos, long lpos) { + Contact c = mListContact.get(pos); + Intent i = new Intent(ContactList.this, Chat.class); + i.setData(c.toUri()); + startActivity(i); + } } - private void assignContactToGroups(List contacts, List groupNames) { - boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false); - mContactOnGroup.clear(); - List all = new LinkedList(); - List noGroups = new LinkedList(); - for (String group: groupNames) { - mContactOnGroup.put(group, new LinkedList()); + /** + * Event simple click on middle groupe name. + */ + private class OnItemClickGroupName implements OnItemClickListener { + + /** + * Constructor. + */ + public OnItemClickGroupName() { } - for (Contact c : contacts) { - if (hideDisconnected && !Status.statusOnline(c.getStatus())) { - continue; - } - all.add(c); - List groups = c.getGroups(); - if (groups.size() == 0) - noGroups.add(c); - else { - for (String currentGroup : groups) { - List contactsByGroups = mContactOnGroup.get(currentGroup); - contactsByGroups.add(c); - } - } + + @Override + public void onItemClick(AdapterView arg0, View v, int i, long l) { + String group = mListGroup.get(i); + buildContactList(group); } - mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups); - mContactOnGroup.put(getString(R.string.contact_list_all_contact), all); } + } diff -r 5f7bbb0c2731 -r 97451b0f4f09 src/com/beem/project/beem/utils/SortedList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/utils/SortedList.java Tue Jun 01 21:32:39 2010 +0200 @@ -0,0 +1,312 @@ +/* + BEEM is a videoconference application on the Android Platform. + + Copyright (C) 2009 by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + This file is part of BEEM. + + BEEM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + BEEM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BEEM. If not, see . + + Please send bug reports with examples or suggestions to + contact@beem-project.com or http://dev.beem-project.com/ + +*/ +package com.beem.project.beem.utils; + +import java.util.List; +import java.util.Comparator; +import java.util.ListIterator; +import java.util.Iterator; +import java.util.Collection; +import java.util.Collections; + +/** + * This class add a sort by insertion to a List. + * All methods which allow you to insert an object at a specific index + * will throw an UnsupportedOperationException. + * + * @author Da Risk + * @param the type of elements maintained by this list + */ +public class SortedList implements List { + + private final List mBackend; + private final Comparator mComparator; + + /** + * Create a SortedList. The existing elements will be sorted. + * + * @param list list to sort + * @param mComparator mComparator to use. + */ + public SortedList(final List list, final Comparator mComparator) { + this.mComparator = mComparator; + this.mBackend = list; + Collections.sort(mBackend, mComparator); + } + + @Override + public int size() { + return mBackend.size(); + } + + @Override + public boolean isEmpty() { + return mBackend.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return mBackend.contains(o); + } + + @Override + public Iterator iterator() { + return new SortedListIterator(mBackend.listIterator()); + } + + @Override + public Object[] toArray() { + return mBackend.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return mBackend.toArray(a); + } + + @Override + public boolean add(E e) { + for (ListIterator it = mBackend.listIterator(); it.hasNext();) { + if (mComparator.compare(e, it.next()) < 0) { + if (it.hasPrevious()) { + it.previous(); + } + it.add(e); + return true; + } + } + mBackend.add(e); + return true; + } + + @Override + public boolean remove(Object o) { + return mBackend.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return mBackend.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + boolean result = false; + for (E e : c) { + boolean t = add(e); + if (t) { + result = t; + } + } + return result; + } + + /** + * Add all the elements in the specified collection. + * The index param is ignored. + * + * @param index ignored + * @param c collection containing elements to be added to this list + * @return true if this list changed as a result of the call + */ + @Override + public boolean addAll(int index, Collection c) { + return addAll(c); + } + + /** + * Add all the elements in the specified collection. + * The index param is ignored. + * + * @param l collection containing elements to be added to this list + * @return true if this list changed as a result of the call + * @see addAll(Collection) + */ + public boolean addAll(SortedList l) { + if (!l.isEmpty()) { + if (mBackend.isEmpty()) { + return mBackend.addAll(l); + } + boolean result = false; + E myfirst = mBackend.get(0); + E last = l.get(l.size() - 1); + E mylast = mBackend.get(mBackend.size() - 1); + E first = l.get(0); + if (mComparator.compare(last, myfirst) < 0) { + result = mBackend.addAll(0, l); + } else if (mComparator.compare(first, mylast) > 0) { + result = mBackend.addAll(l); + } else { + Collection c = l; + result = addAll(c); + } + return result; + } + return false; + } + + @Override + public boolean removeAll(Collection c) { + return mBackend.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return mBackend.retainAll(c); + } + + @Override + public void clear() { + mBackend.clear(); + } + + @Override + public boolean equals(Object o) { + return mBackend.equals(o); + } + + @Override + public int hashCode() { + return mBackend.hashCode(); + } + + @Override + public E get(int index) { + return mBackend.get(index); + } + + @Override + public E set(int index, E element) { + throw new UnsupportedOperationException("set() is not supported in SortedList"); + } + + @Override + public void add(int index, E element) { + throw new UnsupportedOperationException("add at specific index is not supported in SortedList"); + } + + @Override + public E remove(int index) { + return mBackend.remove(index); + } + + @Override + public int indexOf(Object o) { + return mBackend.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return mBackend.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return new SortedListIterator(mBackend.listIterator()); + } + + @Override + public ListIterator listIterator(int index) { + return new SortedListIterator(mBackend.listIterator(index)); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return mBackend.subList(fromIndex, toIndex); + } + + @Override + public String toString() { + return mBackend.toString(); + } + + /** + * A SortedList.iterator don't allow list modification. + * It use the mBackend iterator for the other operations. + */ + private class SortedListIterator implements ListIterator { + + private ListIterator mIt; + + /** + * Construct SortedList.Iterator. + * + * @param iterator the iterator of the backend list + */ + SortedListIterator(final ListIterator iterator) { + mIt = iterator; + } + + @Override + public void add(E e) { + throw new UnsupportedOperationException("add() not supported in SortedList iterator"); + } + + @Override + public boolean hasNext() { + return mIt.hasNext(); + } + + @Override + public E next() { + return mIt.next(); + } + + @Override + public boolean hasPrevious() { + return mIt.hasPrevious(); + } + + @Override + public E previous() { + return mIt.previous(); + } + + @Override + public int nextIndex() { + return mIt.nextIndex(); + } + + @Override + public int previousIndex() { + return mIt.previousIndex(); + } + + @Override + public void remove() { + mIt.remove(); + } + + @Override + public void set(E e) { + throw new UnsupportedOperationException("set () not supported in SortedList iterator"); + } + } +}