001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.tagging.ac; 003 004 import java.util.ArrayList; 005 import java.util.Collection; 006 import java.util.Collections; 007 import java.util.HashMap; 008 import java.util.List; 009 import java.util.Map; 010 011 import javax.swing.JTable; 012 import javax.swing.table.AbstractTableModel; 013 014 /** 015 * AutoCompletionList manages a list of {@link AutoCompletionListItem}s. 016 * 017 * The list is sorted, items with higher priority first, then according to lexicographic order 018 * on the value of the {@link AutoCompletionListItem}. 019 * 020 * AutoCompletionList maintains two views on the list of {@link AutoCompletionListItem}s. 021 * <ol> 022 * <li>the bare, unfiltered view which includes all items</li> 023 * <li>a filtered view, which includes only items which match a current filter expression</li> 024 * </ol> 025 * 026 * AutoCompletionList is an {@link AbstractTableModel} which serves the list of filtered 027 * items to a {@link JTable}. 028 * 029 */ 030 public class AutoCompletionList extends AbstractTableModel { 031 032 /** the bare list of AutoCompletionItems */ 033 private ArrayList<AutoCompletionListItem> list = null; 034 /** the filtered list of AutoCompletionItems */ 035 private ArrayList<AutoCompletionListItem> filtered = null; 036 /** the filter expression */ 037 private String filter = null; 038 /** map from value to priority */ 039 private Map<String,AutoCompletionListItem> valutToItemMap; 040 041 /** 042 * constructor 043 */ 044 public AutoCompletionList() { 045 list = new ArrayList<AutoCompletionListItem>(); 046 filtered = new ArrayList<AutoCompletionListItem>(); 047 valutToItemMap = new HashMap<String, AutoCompletionListItem>(); 048 } 049 050 /** 051 * applies a filter expression to the list of {@link AutoCompletionListItem}s. 052 * 053 * The matching criterion is a case insensitive substring match. 054 * 055 * @param filter the filter expression; must not be null 056 * 057 * @exception IllegalArgumentException thrown, if filter is null 058 */ 059 public void applyFilter(String filter) { 060 if (filter == null) 061 throw new IllegalArgumentException("argument 'filter' must not be null"); 062 this.filter = filter; 063 filter(); 064 } 065 066 /** 067 * clears the current filter 068 * 069 */ 070 public void clearFilter() { 071 filter = null; 072 filter(); 073 } 074 075 /** 076 * @return the current filter expression; null, if no filter expression is set 077 */ 078 public String getFilter() { 079 return filter; 080 } 081 082 /** 083 * adds an AutoCompletionListItem to the list. Only adds the item if it 084 * is not null and if not in the list yet. 085 * 086 * @param item the item 087 */ 088 public void add(AutoCompletionListItem item) { 089 if (item == null) 090 return; 091 appendOrUpdatePriority(item); 092 sort(); 093 filter(); 094 } 095 096 /** 097 * adds another AutoCompletionList to this list. An item is only 098 * added it is not null and if it does not exist in the list yet. 099 * 100 * @param other another auto completion list; must not be null 101 * @exception IllegalArgumentException thrown, if other is null 102 */ 103 public void add(AutoCompletionList other) { 104 if (other == null) 105 throw new IllegalArgumentException("argument 'other' must not be null"); 106 for (AutoCompletionListItem item : other.list) { 107 appendOrUpdatePriority(item); 108 } 109 sort(); 110 filter(); 111 } 112 113 /** 114 * adds a list of AutoCompletionListItem to this list. Only items which 115 * are not null and which do not exist yet in the list are added. 116 * 117 * @param other a list of AutoCompletionListItem; must not be null 118 * @exception IllegalArgumentException thrown, if other is null 119 */ 120 public void add(List<AutoCompletionListItem> other) { 121 if (other == null) 122 throw new IllegalArgumentException("argument 'other' must not be null"); 123 for (AutoCompletionListItem toadd : other) { 124 appendOrUpdatePriority(toadd); 125 } 126 sort(); 127 filter(); 128 } 129 130 /** 131 * adds a list of strings to this list. Only strings which 132 * are not null and which do not exist yet in the list are added. 133 * 134 * @param value a list of strings to add 135 * @param priority the priority to use 136 */ 137 public void add(Collection<String> values, AutoCompletionItemPritority priority) { 138 if (values == null) return; 139 for (String value: values) { 140 if (value == null) { 141 continue; 142 } 143 AutoCompletionListItem item = new AutoCompletionListItem(value,priority); 144 appendOrUpdatePriority(item); 145 146 } 147 sort(); 148 filter(); 149 } 150 151 protected void appendOrUpdatePriority(AutoCompletionListItem toAdd) { 152 AutoCompletionListItem item = valutToItemMap.get(toAdd.getValue()); 153 if (item == null) { 154 // new item does not exist yet. Add it to the list 155 list.add(toAdd); 156 valutToItemMap.put(toAdd.getValue(), toAdd); 157 } else { 158 item.setPriority(item.getPriority().mergeWith(toAdd.getPriority())); 159 } 160 } 161 162 /** 163 * checks whether a specific item is already in the list. Matches for the 164 * the value <strong>and</strong> the priority of the item 165 * 166 * @param item the item to check 167 * @return true, if item is in the list; false, otherwise 168 */ 169 public boolean contains(AutoCompletionListItem item) { 170 if (item == null) 171 return false; 172 return list.contains(item); 173 } 174 175 /** 176 * checks whether an item with the given value is already in the list. Ignores 177 * priority of the items. 178 * 179 * @param value the value of an auto completion item 180 * @return true, if value is in the list; false, otherwise 181 */ 182 public boolean contains(String value) { 183 if (value == null) 184 return false; 185 for (AutoCompletionListItem item: list) { 186 if (item.getValue().equals(value)) 187 return true; 188 } 189 return false; 190 } 191 192 /** 193 * removes the auto completion item with key <code>key</code> 194 * @param key the key; 195 */ 196 public void remove(String key) { 197 if (key == null) 198 return; 199 for (int i=0;i< list.size();i++) { 200 AutoCompletionListItem item = list.get(i); 201 if (item.getValue().equals(key)) { 202 list.remove(i); 203 return; 204 } 205 } 206 } 207 208 /** 209 * sorts the list 210 */ 211 protected void sort() { 212 Collections.sort(list); 213 } 214 215 protected void filter() { 216 filtered.clear(); 217 if (filter == null) { 218 // Collections.copy throws an exception "Source does not fit in dest" 219 // Collections.copy(filtered, list); 220 filtered.ensureCapacity(list.size()); 221 for (AutoCompletionListItem item: list) { 222 filtered.add(item); 223 } 224 return; 225 } 226 227 // apply the pattern to list of possible values. If it matches, add the 228 // value to the list of filtered values 229 // 230 for (AutoCompletionListItem item : list) { 231 if (item.getValue().startsWith(filter)) { 232 filtered.add(item); 233 } 234 } 235 fireTableDataChanged(); 236 } 237 238 /** 239 * replies the number of filtered items 240 * 241 * @return the number of filtered items 242 */ 243 public int getFilteredSize() { 244 return this.filtered.size(); 245 } 246 247 /** 248 * replies the idx-th item from the list of filtered items 249 * @param idx the index; must be in the range 0<= idx < {@link #getFilteredSize()} 250 * @return the item 251 * 252 * @exception IndexOutOfBoundsException thrown, if idx is out of bounds 253 */ 254 public AutoCompletionListItem getFilteredItem(int idx) { 255 if (idx < 0 || idx >= getFilteredSize()) 256 throw new IndexOutOfBoundsException("idx out of bounds. idx=" + idx); 257 return filtered.get(idx); 258 } 259 260 ArrayList<AutoCompletionListItem> getList() { 261 return list; 262 } 263 264 List<AutoCompletionListItem> getUnmodifiableList() { 265 return Collections.unmodifiableList(list); 266 } 267 268 /** 269 * removes all elements from the auto completion list 270 * 271 */ 272 public void clear() { 273 valutToItemMap.clear(); 274 list.clear(); 275 fireTableDataChanged(); 276 } 277 278 public int getColumnCount() { 279 return 1; 280 } 281 282 public int getRowCount() { 283 284 return list == null ? 0 : getFilteredSize(); 285 } 286 287 public Object getValueAt(int rowIndex, int columnIndex) { 288 return list == null ? null : getFilteredItem(rowIndex); 289 } 290 291 public void dump() { 292 System.out.println("---------------------------------"); 293 for (AutoCompletionListItem item: list) { 294 System.out.println(item); 295 } 296 System.out.println("---------------------------------"); 297 } 298 }