/*
* Copyright (C) 2011 Virginia Tech Department of Computer Science
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sofia.widget;
import sofia.util.ObservableList;
import android.content.Context;
import android.util.AttributeSet;
import java.util.Collection;
import java.util.List;
//-------------------------------------------------------------------------
/**
* A subclass of {@link android.widget.AutoCompleteTextView} that is easier to
* use. It provides methods like those in the {@link List} interface
* ({@code add}, {@code remove}, {@code get}, and {@code set}, among others) to
* manipulate the contents of the list, as well as an accessor method
* {@link #getList()} that returns a {@link List} that automatically refreshes
* the list when its structure is changed.
*
* @param <E> the type of elements stored in the {@code AutoCompleteTextView}
*
* @author Tony Allevato
*/
public class AutoCompleteTextView<E>
extends android.widget.AutoCompleteTextView
{
//~ Fields ................................................................
private ObservableList<E> list;
private DecoratingAdapter<E> adapter;
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new {@code AutoCompleteTextView}.
*
* @param context the context
*/
public AutoCompleteTextView(Context context)
{
super(context);
init(null);
}
// ----------------------------------------------------------
/**
* Creates a new {@code AutoCompleteTextView}.
*
* @param context the context
* @param attrs the attribute set from the layout XML file
*/
public AutoCompleteTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
init(null);
}
// ----------------------------------------------------------
/**
* Creates a new {@code AutoCompleteTextView}.
*
* @param context the context
* @param attrs the attribute set from the layout XML file
* @param defStyle the default style ID
*/
public AutoCompleteTextView(
Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init(null);
}
//~ Public methods ........................................................
// ----------------------------------------------------------
/**
* Gets the list of items that is managed by this text view. Changes made
* to the structure of the list returned by this method (that is, adding,
* removing, or replacing items) will be immediately reflected in the list
* view. You only need to explicitly {@link #refresh()} the list if you
* make a change to an element inside the list without directly modifying
* the list itself.
*
* @return the {@link List} of items managed by this text view
*/
public List<E> getList()
{
return list;
}
// ----------------------------------------------------------
/**
* Adds an item to the text view.
*
* @param item the item to add to the text view
* @return true if the item could be added, or false if it could not
*/
public boolean add(E item)
{
return list.add(item);
}
// ----------------------------------------------------------
/**
* Inserts an item into the text view at the specified index.
*
* @param index the index where the new item should be inserted
* @param item the item to add to the text view
*/
public void add(int index, E item)
{
list.add(index, item);
}
// ----------------------------------------------------------
/**
* Adds the items in the specified collection to the text view.
*
* @param collection the items to add to the text view
* @return rue if the items could be added, or false if they could not
*/
public boolean addAll(Collection<? extends E> collection)
{
return list.addAll(collection);
}
// ----------------------------------------------------------
/**
* Inserts the items in the specified collection into the text view at the
* specified index.
*
* @param index the index where the new items should be inserted
* @param collection the items to add to the text view
* @return true if the items could be added, or false if they could not
*/
public boolean addAll(int index, Collection<? extends E> collection)
{
return list.addAll(index, collection);
}
// ----------------------------------------------------------
/**
* Removes all items from the text view.
*/
public void clear()
{
list.clear();
}
// ----------------------------------------------------------
/**
* Gets the element at the specified index from the text view.
*
* @param index the index of the item to retrieve
* @return the item at the specified index
*/
public E get(int index)
{
return list.get(index);
}
// ----------------------------------------------------------
/**
* Removes the item at the specified index from the text view.
*
* @param index the index of the item to be removed
* @return the item that was removed
*/
public E remove(int index)
{
return list.remove(index);
}
// ----------------------------------------------------------
/**
* Removes the specified item from the text view.
*
* @param item the item to remove from the text view
* @return true if the item was found and removed, or false if it was not
*/
public boolean remove(E item)
{
return list.remove(item);
}
// ----------------------------------------------------------
/**
* Replaces the element at the specified index from the text view with
* another item.
*
* @param index the index of the item to retrieve
* @param item the item to put into the list
* @return the item previously at the specified index
*/
public E set(int index, E item)
{
return list.set(index, item);
}
// ----------------------------------------------------------
/**
* Refreshes the text view to update its contents from the list it manages.
* This method does not need to be called after methods like {@code add}
* or {@code remove} -- it only needs to be called if you change a property
* of one of the elements in the list (for example, by calling a setter)
* without modifying the structure of the list itself.
*/
public void refresh()
{
adapter.notifyDataSetChanged();
}
//~ Private methods .......................................................
// ----------------------------------------------------------
/**
* Common initialization for new text views.
*/
private void init(AttributeSet attrs)
{
list = new ObservableList<E>();
adapter = new DecoratingAdapter<E>(getContext(),
android.R.layout.simple_dropdown_item_1line, list);
setAdapter(adapter);
list.addObserver(observer);
}
//~ Inner classes .........................................................
// ----------------------------------------------------------
/**
* The observer is pulled into a separate object so that we do not expose
* the changeWasObserved method in the class's public interface.
*/
private final Object observer = new Object()
{
// ----------------------------------------------------------
/**
* Handles notifications about a change to the list inside this list
* view.
*
* @param theList the list that was changed
*/
@SuppressWarnings("unused")
public void changeWasObserved(ObservableList<E> theList)
{
refresh();
}
};
}