001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.tagging.ac; 003 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.Collections; 007import java.util.Set; 008 009import javax.swing.JTable; 010import javax.swing.table.AbstractTableModel; 011 012import org.openstreetmap.josm.data.tagging.ac.AutoCompletionItem; 013import org.openstreetmap.josm.data.tagging.ac.AutoCompletionPriority; 014import org.openstreetmap.josm.data.tagging.ac.AutoCompletionSet; 015import org.openstreetmap.josm.tools.CheckParameterUtil; 016 017/** 018 * AutoCompletionList manages a graphical list of {@link AutoCompletionItem}s. 019 * 020 * The list is sorted, items with higher priority first, then according to lexicographic order 021 * on the value of the {@link AutoCompletionItem}. 022 * 023 * AutoCompletionList maintains two views on the list of {@link AutoCompletionItem}s. 024 * <ol> 025 * <li>the bare, unfiltered view which includes all items</li> 026 * <li>a filtered view, which includes only items which match a current filter expression</li> 027 * </ol> 028 * 029 * AutoCompletionList is an {@link AbstractTableModel} which serves the list of filtered 030 * items to a {@link JTable}. 031 * @since 1762 032 */ 033public class AutoCompletionList extends AbstractTableModel { 034 035 /** the bare list of AutoCompletionItems */ 036 private final transient AutoCompletionSet list; 037 /** the filtered list of AutoCompletionItems */ 038 private final transient ArrayList<AutoCompletionItem> filtered; 039 /** the filter expression */ 040 private String filter; 041 042 /** 043 * constructor 044 */ 045 public AutoCompletionList() { 046 list = new AutoCompletionSet(); 047 filtered = new ArrayList<>(); 048 } 049 050 /** 051 * applies a filter expression to the list of {@link AutoCompletionItem}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 * @throws IllegalArgumentException if filter is null 058 */ 059 public void applyFilter(String filter) { 060 CheckParameterUtil.ensureParameterNotNull(filter, "filter"); 061 this.filter = filter; 062 filter(); 063 } 064 065 /** 066 * clears the current filter 067 */ 068 public void clearFilter() { 069 filter = null; 070 filter(); 071 } 072 073 /** 074 * Returns the current filter expression. 075 * @return the current filter expression; null, if no filter expression is set 076 */ 077 public String getFilter() { 078 return filter; 079 } 080 081 /** 082 * adds an {@link AutoCompletionItem} to the list. Only adds the item if it 083 * is not null and if not in the list yet. 084 * 085 * @param item the item 086 * @since 12859 087 */ 088 public void add(AutoCompletionItem item) { 089 if (item != null && list.add(item)) { 090 filter(); 091 } 092 } 093 094 /** 095 * adds another {@link AutoCompletionList} to this list. An item is only 096 * added it is not null and if it does not exist in the list yet. 097 * 098 * @param other another auto completion list; must not be null 099 * @throws IllegalArgumentException if other is null 100 */ 101 public void add(AutoCompletionList other) { 102 CheckParameterUtil.ensureParameterNotNull(other, "other"); 103 add(other.list); 104 } 105 106 /** 107 * adds a collection of {@link AutoCompletionItem} to this list. An item is only 108 * added it is not null and if it does not exist in the list yet. 109 * 110 * @param collection auto completion collection; must not be null 111 * @throws IllegalArgumentException if other is null 112 * @since 12859 113 */ 114 public void add(Collection<AutoCompletionItem> collection) { 115 CheckParameterUtil.ensureParameterNotNull(collection, "collection"); 116 if (list.addAll(collection)) { 117 filter(); 118 } 119 } 120 121 /** 122 * adds a list of strings to this list. Only strings which 123 * are not null and which do not exist yet in the list are added. 124 * 125 * @param values a list of strings to add 126 * @param priority the priority to use 127 * @since 12859 128 */ 129 public void add(Collection<String> values, AutoCompletionPriority priority) { 130 if (values != null && list.addAll(values, priority)) { 131 filter(); 132 } 133 } 134 135 /** 136 * Adds values that have been entered by the user. 137 * @param values values that have been entered by the user 138 */ 139 public void addUserInput(Collection<String> values) { 140 if (values != null && list.addUserInput(values)) { 141 filter(); 142 } 143 } 144 145 /** 146 * checks whether a specific item is already in the list. Matches for the 147 * the value <strong>and</strong> the priority of the item 148 * 149 * @param item the item to check 150 * @return true, if item is in the list; false, otherwise 151 * @since 12859 152 */ 153 public boolean contains(AutoCompletionItem item) { 154 return list.contains(item); 155 } 156 157 /** 158 * checks whether an item with the given value is already in the list. Ignores 159 * priority of the items. 160 * 161 * @param value the value of an auto completion item 162 * @return true, if value is in the list; false, otherwise 163 */ 164 public boolean contains(String value) { 165 return list.contains(value); 166 } 167 168 /** 169 * removes the auto completion item with key <code>key</code> 170 * @param key the key 171 */ 172 public void remove(String key) { 173 if (key != null) { 174 list.remove(key); 175 } 176 } 177 178 protected void filter() { 179 filtered.clear(); 180 if (filter == null) { 181 // Collections.copy throws an exception "Source does not fit in dest" 182 filtered.ensureCapacity(list.size()); 183 filtered.addAll(list); 184 return; 185 } 186 187 // apply the pattern to list of possible values. If it matches, add the 188 // value to the list of filtered values 189 // 190 list.stream().filter(e -> e.getValue().startsWith(filter)).forEach(filtered::add); 191 fireTableDataChanged(); 192 } 193 194 /** 195 * replies the number of filtered items 196 * 197 * @return the number of filtered items 198 */ 199 public int getFilteredSize() { 200 return filtered.size(); 201 } 202 203 /** 204 * replies the idx-th item from the list of filtered items 205 * @param idx the index; must be in the range 0 <= idx < {@link #getFilteredSize()} 206 * @return the item 207 * 208 * @throws IndexOutOfBoundsException if idx is out of bounds 209 * @since 12859 210 */ 211 public AutoCompletionItem getFilteredItemAt(int idx) { 212 return filtered.get(idx); 213 } 214 215 AutoCompletionSet getSet() { 216 return list; 217 } 218 219 Set<AutoCompletionItem> getUnmodifiableSet() { 220 return Collections.unmodifiableSet(list); 221 } 222 223 /** 224 * removes all elements from the auto completion list 225 */ 226 public void clear() { 227 list.clear(); 228 fireTableDataChanged(); 229 } 230 231 @Override 232 public int getColumnCount() { 233 return 1; 234 } 235 236 @Override 237 public int getRowCount() { 238 return list == null ? 0 : getFilteredSize(); 239 } 240 241 @Override 242 public Object getValueAt(int rowIndex, int columnIndex) { 243 return list == null ? null : getFilteredItemAt(rowIndex); 244 } 245}