1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.quicksearchbox;
18 
19 import com.google.common.annotations.VisibleForTesting;
20 
21 import android.database.DataSetObservable;
22 import android.database.DataSetObserver;
23 
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashSet;
27 
28 /**
29  * A SuggestionCursor that is backed by a list of Suggestions.
30  */
31 public class ListSuggestionCursor extends AbstractSuggestionCursorWrapper {
32 
33     private static final int DEFAULT_CAPACITY = 16;
34 
35     private final DataSetObservable mDataSetObservable = new DataSetObservable();
36 
37     private final ArrayList<Entry> mSuggestions;
38 
39     private HashSet<String> mExtraColumns;
40 
41     private int mPos = 0;
42 
ListSuggestionCursor(String userQuery)43     public ListSuggestionCursor(String userQuery) {
44         this(userQuery, DEFAULT_CAPACITY);
45     }
46 
47     @VisibleForTesting
ListSuggestionCursor(String userQuery, Suggestion...suggestions)48     public ListSuggestionCursor(String userQuery, Suggestion...suggestions) {
49         this(userQuery, suggestions.length);
50         for (Suggestion suggestion : suggestions) {
51             add(suggestion);
52         }
53     }
54 
ListSuggestionCursor(String userQuery, int capacity)55     public ListSuggestionCursor(String userQuery, int capacity) {
56         super(userQuery);
57         mSuggestions = new ArrayList<Entry>(capacity);
58     }
59 
60     /**
61      * Adds a suggestion from another suggestion cursor.
62      *
63      * @return {@code true} if the suggestion was added.
64      */
add(Suggestion suggestion)65     public boolean add(Suggestion suggestion) {
66         mSuggestions.add(new Entry(suggestion));
67         return true;
68     }
69 
close()70     public void close() {
71         mSuggestions.clear();
72     }
73 
getPosition()74     public int getPosition() {
75         return mPos;
76     }
77 
moveTo(int pos)78     public void moveTo(int pos) {
79         mPos = pos;
80     }
81 
moveToNext()82     public boolean moveToNext() {
83         int size = mSuggestions.size();
84         if (mPos >= size) {
85             // Already past the end
86             return false;
87         }
88         mPos++;
89         return mPos < size;
90     }
91 
removeRow()92     public void removeRow() {
93         mSuggestions.remove(mPos);
94     }
95 
replaceRow(Suggestion suggestion)96     public void replaceRow(Suggestion suggestion) {
97         mSuggestions.set(mPos, new Entry(suggestion));
98     }
99 
getCount()100     public int getCount() {
101         return mSuggestions.size();
102     }
103 
104     @Override
current()105     protected Suggestion current() {
106         return mSuggestions.get(mPos).get();
107     }
108 
109     @Override
toString()110     public String toString() {
111         return getClass().getSimpleName() + "{[" + getUserQuery() + "] " + mSuggestions + "}";
112     }
113 
114     /**
115      * Register an observer that is called when changes happen to this data set.
116      *
117      * @param observer gets notified when the data set changes.
118      */
registerDataSetObserver(DataSetObserver observer)119     public void registerDataSetObserver(DataSetObserver observer) {
120         mDataSetObservable.registerObserver(observer);
121     }
122 
123     /**
124      * Unregister an observer that has previously been registered with
125      * {@link #registerDataSetObserver(DataSetObserver)}
126      *
127      * @param observer the observer to unregister.
128      */
unregisterDataSetObserver(DataSetObserver observer)129     public void unregisterDataSetObserver(DataSetObserver observer) {
130         mDataSetObservable.unregisterObserver(observer);
131     }
132 
notifyDataSetChanged()133     protected void notifyDataSetChanged() {
134         mDataSetObservable.notifyChanged();
135     }
136 
137     @Override
getExtras()138     public SuggestionExtras getExtras() {
139         // override with caching to avoid re-parsing the extras
140         return mSuggestions.get(mPos).getExtras();
141     }
142 
getExtraColumns()143    public Collection<String> getExtraColumns() {
144         if (mExtraColumns == null) {
145             mExtraColumns = new HashSet<String>();
146             for (Entry e : mSuggestions) {
147                 SuggestionExtras extras = e.getExtras();
148                 Collection<String> extraColumns = extras == null ? null
149                         : extras.getExtraColumnNames();
150                 if (extraColumns != null) {
151                     for (String column : extras.getExtraColumnNames()) {
152                         mExtraColumns.add(column);
153                     }
154                 }
155             }
156         }
157         return mExtraColumns.isEmpty() ? null : mExtraColumns;
158     }
159 
160     /**
161      * This class exists purely to cache the suggestion extras.
162      */
163     private static class Entry {
164         private final Suggestion mSuggestion;
165         private SuggestionExtras mExtras;
Entry(Suggestion s)166         public Entry(Suggestion s) {
167             mSuggestion = s;
168         }
get()169         public Suggestion get() {
170             return mSuggestion;
171         }
getExtras()172         public SuggestionExtras getExtras() {
173             if (mExtras == null) {
174                 mExtras = mSuggestion.getExtras();
175             }
176             return mExtras;
177         }
178     }
179 
180 }
181