package edu.mit.mobile.android.locast.widget;
/*
* Copyright (C) 2010 MIT Mobile Experience Lab
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import edu.mit.mobile.android.locast.ver2.R;
/**
* A user-modifiable set of free tags. The user can add a new tag to a set of available tags
* or choose from a set of recommended tags.
*
* @author stevep
*
*/
public class TagList extends TagListView implements OnEditorActionListener, OnClickListener, OnFocusChangeListener {
private ViewGroup recommendedTagView;
private TextView recommendedTagLabel;
private AutoCompleteTextView addTagEditText;
private final List<String> recommendedTags = new Vector<String>();
private final List<String> shownRecs = new Vector<String>();
private int style;
//private static ArrayAdapter<String> acAdapter;
private static RemoteTagsAdapter acAdapter;
public TagList(Context context) {
super(context);
init(context);
}
public TagList(Context context, AttributeSet attrs){
super(context, attrs);
init(context);
}
private void init(Context context){
recommendedTagView = (ViewGroup)findViewById(R.id.tag_recommended_tags);
recommendedTagLabel = (TextView)findViewById(R.id.tag_recommended_label);
addTagEditText = (AutoCompleteTextView)findViewById(R.id.tag_add_text);
((ImageButton)findViewById(R.id.tag_add_button)).setOnClickListener(this);
setOnTagClickListener(this);
acAdapter = new RemoteTagsAdapter(context, android.R.layout.simple_dropdown_item_1line);
addTagEditText.setOnFocusChangeListener(this);
addTagEditText.setAdapter(acAdapter);
addTagEditText.setOnEditorActionListener(this);
}
@Override
protected void inflateLayout(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.taglist, this);
final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagList);
style = ta.getInt(R.styleable.TagList_taglist_type, R.id.full);
if (style == R.id.selector){
findViewById(R.id.tag_manual_entry).setVisibility(View.GONE);
findViewById(R.id.tag_recommended_label).setVisibility(View.GONE);
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
addTagEditText.setEnabled(enabled);
recommendedTagView.setEnabled(enabled);
findViewById(R.id.tag_add_button).setEnabled(enabled);
}
@Override
public boolean addTag(String tag) {
if (! super.addTag(tag)) {
return false;
}
if (recommendedTags.contains(tag)){
recommendedTagView.removeViewAt(shownRecs.indexOf(tag));
shownRecs.remove(tag);
if (shownRecs.size() == 0){
recommendedTagLabel.setVisibility(TextView.GONE);
}
}
return true;
}
@Override
public boolean removeTag(String tag) {
if(! super.removeTag(tag)) {
return false;
}
if (recommendedTags.contains(tag) && !shownRecs.contains(tag)){
shownRecs.add(tag);
Collections.sort(shownRecs);
recommendedTagLabel.setVisibility(TextView.VISIBLE);
recommendedTagView.addView(getTagView(tag, false), shownRecs.indexOf(tag));
}
return true;
}
/**
* A list of tags that are recommended for the given item.
*
* @param tag
*/
public void addRecommendedTag(String tag){
if (tag.length() == 0) {
throw new IllegalArgumentException("cannot add empty tag");
}
if (! recommendedTags.contains(tag)){
recommendedTags.add(tag);
if (! getTags().contains(tag)){
shownRecs.add(tag);
Collections.sort(shownRecs);
recommendedTagLabel.setVisibility(TextView.VISIBLE);
recommendedTagView.addView(getTagView(tag, false), shownRecs.indexOf(tag));
}
}
}
public void addedRecommendedTags(List <String> tags){
for (final String tag: tags){
addRecommendedTag(tag);
}
}
@Override
public void clearAllTags(){
super.clearAllTags();
clearRecommendedTags();
}
public void clearRecommendedTags(){
recommendedTags.clear();
shownRecs.clear();
recommendedTagView.removeAllViews();
recommendedTagLabel.setVisibility(TextView.GONE);
}
@Override
TagButton getTagView(String tag, boolean added){
final TagButton b = new TagButton(getContext(), tag, added, true);
b.setOnClickListener(this);
return b;
}
/**
* Listener to handle the act of clicking on a tag button.
*/
public void onClick(View v) {
boolean changed = false;
switch (v.getId()){
case R.id.tag_add_button:
changed = addEditTextTag();
break;
default:
if (v instanceof TagButton){
final TagButton tagButton = (TagButton)v;
if (tagButton.isAdded()){
changed = removeTag((String)tagButton.getTag());
}else{
changed = addTag((String)tagButton.getTag());
}
}
}
if (changed && listener != null){
listener.onTagListChange(this);
}
}
private boolean addEditTextTag(){
boolean changed = false;
String tag = addTagEditText.getText().toString();
tag = tag.trim();
tag = tag.toLowerCase();
if (tag.length() > 0){
changed = addTag(tag);
addTagEditText.setText("");
}
return changed;
}
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (v.getId()){
case R.id.tag_add_text:
if (addEditTextTag() && listener != null){
listener.onTagListChange(this);
}
return true;
}
return false;
}
static class SavedState extends BaseSavedState{
private final List<String> addedTags;
private final List<String> recTags;
SavedState(Parcelable superState, List<String>addedTags, List<String>recTags) {
super(superState);
this.addedTags = addedTags;
this.recTags = recTags;
}
@SuppressWarnings("unchecked")
private SavedState(Parcel in) {
super(in);
addedTags = in.readArrayList(String.class.getClassLoader());
recTags = in.readArrayList(String.class.getClassLoader());
}
public List<String> getAddedTags() {
return addedTags;
}
public List<String> getRecTags() {
return recTags;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeList(addedTags);
dest.writeList(recTags);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState, getTags(), recommendedTags);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
final SavedState ss = (SavedState)state;
super.onRestoreInstanceState(ss.getSuperState());
clearAllTags();
addTags(ss.getAddedTags());
addedRecommendedTags(ss.getRecTags());
}
private OnTagListChangeListener listener = null;
public void setOnTagListChangeListener(OnTagListChangeListener listener){
this.listener = listener;
}
public interface OnTagListChangeListener {
public void onTagListChange(TagList v);
}
public void onFocusChange(View v, boolean hasFocus) {
switch (v.getId()){
case R.id.tag_add_text:
if (hasFocus){
acAdapter.refreshTags();
}
break;
}
}
}