package org.openstreetmap.josm.gui.tagging.ac;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/**
* AutoCompletionList manages a list of {@see AutoCompletionListItem}s.
*
* The list is sorted, items with higher priority first, then according to lexicographic order
* on the value of the {@see AutoCompletionListItem}.
*
* AutoCompletionList maintains two views on the list of {@see AutoCompletionListItem}s.
* <ol>
* <li>the bare, unfiltered view which includes all items</li>
* <li>a filtered view, which includes only items which match a current filter expression</li>
* </ol>
*
* AutoCompletionList is an {@link AbstractTableModel} which serves the list of filtered
* items to a {@link JTable}.
*
*/
public class AutoCompletionList extends AbstractTableModel {
/** the bare list of AutoCompletionItems */
private ArrayList<AutoCompletionListItem> list = null;
/** the filtered list of AutoCompletionItems */
private ArrayList<AutoCompletionListItem> filtered = null;
/** the filter expression */
private String filter = null;
/** map from value to priority */
private Map<String,AutoCompletionListItem> valutToItemMap;
/**
* constructor
*/
public AutoCompletionList() {
list = new ArrayList<AutoCompletionListItem>();
filtered = new ArrayList<AutoCompletionListItem>();
valutToItemMap = new HashMap<String, AutoCompletionListItem>();
}
/**
* applies a filter expression to the list of {@see AutoCompletionListItem}s.
*
* The matching criterion is a case insensitive substring match.
*
* @param filter the filter expression; must not be null
*
* @exception IllegalArgumentException thrown, if filter is null
*/
public void applyFilter(String filter) {
if (filter == null)
throw new IllegalArgumentException("argument 'filter' must not be null");
this.filter = filter;
filter();
}
/**
* clears the current filter
*
*/
public void clearFilter() {
filter = null;
filter();
}
/**
* @return the current filter expression; null, if no filter expression is set
*/
public String getFilter() {
return filter;
}
/**
* adds an AutoCompletionListItem to the list. Only adds the item if it
* is not null and if not in the list yet.
*
* @param item the item
*/
public void add(AutoCompletionListItem item) {
if (item == null)
return;
appendOrUpdatePriority(item);
sort();
filter();
}
/**
* adds another AutoCompletionList to this list. An item is only
* added it is not null and if it does not exist in the list yet.
*
* @param other another auto completion list; must not be null
* @exception IllegalArgumentException thrown, if other is null
*/
public void add(AutoCompletionList other) {
if (other == null)
throw new IllegalArgumentException("argument 'other' must not be null");
for (AutoCompletionListItem item : other.list) {
appendOrUpdatePriority(item);
}
sort();
filter();
}
/**
* adds a list of AutoCompletionListItem to this list. Only items which
* are not null and which do not exist yet in the list are added.
*
* @param other a list of AutoCompletionListItem; must not be null
* @exception IllegalArgumentException thrown, if other is null
*/
public void add(List<AutoCompletionListItem> other) {
if (other == null)
throw new IllegalArgumentException("argument 'other' must not be null");
for (AutoCompletionListItem toadd : other) {
appendOrUpdatePriority(toadd);
}
sort();
filter();
}
/**
* adds a list of strings to this list. Only strings which
* are not null and which do not exist yet in the list are added.
*
* @param value a list of strings to add
* @param priority the priority to use
*/
public void add(Collection<String> values, AutoCompletionItemPritority priority) {
if (values == null) return;
for (String value: values) {
if (value == null) {
continue;
}
AutoCompletionListItem item = new AutoCompletionListItem(value,priority);
appendOrUpdatePriority(item);
}
sort();
filter();
}
protected void appendOrUpdatePriority(AutoCompletionListItem toadd) {
AutoCompletionListItem item = valutToItemMap.get(toadd.getValue());
if (item == null) {
// new item does not exist yet. Add it to the list
//
list.add(toadd);
valutToItemMap.put(toadd.getValue(), toadd);
} else {
// new item already exists. Update priority if necessary
// If it is both in the dataset and in the presets, update the priority.
final AutoCompletionItemPritority IS_IN_DATASET = AutoCompletionItemPritority.IS_IN_DATASET;
final AutoCompletionItemPritority IS_IN_STANDARD = AutoCompletionItemPritority.IS_IN_STANDARD;
if ((toadd.getPriority() == IS_IN_STANDARD && item.getPriority() == IS_IN_DATASET) ||
(toadd.getPriority() == IS_IN_DATASET && item.getPriority() == IS_IN_STANDARD)) {
item.setPriority(AutoCompletionItemPritority.IS_IN_STANDARD_AND_IN_DATASET);
} else {
if (toadd.getPriority().compareTo(item.getPriority()) < 0) {
item.setPriority(toadd.getPriority());
}
}
}
}
/**
* checks whether a specific item is already in the list. Matches for the
* the value <strong>and</strong> the priority of the item
*
* @param item the item to check
* @return true, if item is in the list; false, otherwise
*/
public boolean contains(AutoCompletionListItem item) {
if (item == null)
return false;
return list.contains(item);
}
/**
* checks whether an item with the given value is already in the list. Ignores
* priority of the items.
*
* @param value the value of an auto completion item
* @return true, if value is in the list; false, otherwise
*/
public boolean contains(String value) {
if (value == null)
return false;
for (AutoCompletionListItem item: list) {
if (item.getValue().equals(value))
return true;
}
return false;
}
/**
* removes the auto completion item with key <code>key</code>
* @param key the key;
*/
public void remove(String key) {
if (key == null)
return;
for (int i=0;i< list.size();i++) {
AutoCompletionListItem item = list.get(i);
if (item.getValue().equals(key)) {
list.remove(i);
return;
}
}
}
/**
* sorts the list
*/
protected void sort() {
Collections.sort(list);
}
protected void filter() {
filtered.clear();
if (filter == null) {
// Collections.copy throws an exception "Source does not fit in dest"
// Collections.copy(filtered, list);
filtered.ensureCapacity(list.size());
for (AutoCompletionListItem item: list) {
filtered.add(item);
}
return;
}
// apply the pattern to list of possible values. If it matches, add the
// value to the list of filtered values
//
for (AutoCompletionListItem item : list) {
if (item.getValue().startsWith(filter)) {
filtered.add(item);
}
}
fireTableDataChanged();
}
/**
* replies the number of filtered items
*
* @return the number of filtered items
*/
public int getFilteredSize() {
return this.filtered.size();
}
/**
* replies the idx-th item from the list of filtered items
* @param idx the index; must be in the range 0<= idx < {@see #getFilteredSize()}
* @return the item
*
* @exception IndexOutOfBoundsException thrown, if idx is out of bounds
*/
public AutoCompletionListItem getFilteredItem(int idx) {
if (idx < 0 || idx >= getFilteredSize())
throw new IndexOutOfBoundsException("idx out of bounds. idx=" + idx);
return filtered.get(idx);
}
/**
* removes all elements from the auto completion list
*
*/
public void clear() {
valutToItemMap.clear();
list.clear();
fireTableDataChanged();
}
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return list == null ? 0 : getFilteredSize();
}
public Object getValueAt(int rowIndex, int columnIndex) {
return list == null ? null : getFilteredItem(rowIndex);
}
public void dump() {
System.out.println("---------------------------------");
for (AutoCompletionListItem item: list) {
System.out.println(item.getValue());
}
System.out.println("---------------------------------");
}
}