001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.util.ArrayList; 005import java.util.Iterator; 006import java.util.List; 007import java.util.NoSuchElementException; 008 009import javax.swing.DefaultComboBoxModel; 010 011import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem; 012 013/** 014 * A data model for {@link HistoryComboBox} 015 */ 016class ComboBoxHistory extends DefaultComboBoxModel<AutoCompletionListItem> implements Iterable<AutoCompletionListItem> { 017 018 private final int maxSize; 019 020 private final transient List<HistoryChangedListener> listeners = new ArrayList<>(); 021 022 /** 023 * Constructs a {@code ComboBoxHistory} keeping track of {@code maxSize} items 024 * @param size the history size 025 */ 026 ComboBoxHistory(int size) { 027 maxSize = size; 028 } 029 030 /** 031 * Adds or moves an element to the top of the history 032 * @param s the element to add 033 */ 034 public void addElement(String s) { 035 addElement(new AutoCompletionListItem(s)); 036 } 037 038 /** 039 * Adds or moves an element to the top of the history 040 * @param o the element to add 041 */ 042 @Override 043 public void addElement(AutoCompletionListItem o) { 044 String newEntry = o.getValue(); 045 046 // if history contains this object already, delete it, 047 // so that it looks like a move to the top 048 for (int i = 0; i < getSize(); i++) { 049 String oldEntry = getElementAt(i).getValue(); 050 if (oldEntry.equals(newEntry)) { 051 removeElementAt(i); 052 } 053 } 054 055 // insert element at the top 056 insertElementAt(o, 0); 057 058 // remove an element, if the history gets too large 059 if (getSize() > maxSize) { 060 removeElementAt(getSize()-1); 061 } 062 063 // set selected item to the one just added 064 setSelectedItem(o); 065 066 fireHistoryChanged(); 067 } 068 069 @Override 070 public Iterator<AutoCompletionListItem> iterator() { 071 return new Iterator<AutoCompletionListItem>() { 072 073 private int position = -1; 074 075 @Override 076 public void remove() { 077 removeElementAt(position); 078 } 079 080 @Override 081 public boolean hasNext() { 082 return position < getSize()-1 && getSize() > 0; 083 } 084 085 @Override 086 public AutoCompletionListItem next() { 087 if (!hasNext()) 088 throw new NoSuchElementException(); 089 position++; 090 return getElementAt(position); 091 } 092 }; 093 } 094 095 /** 096 * {@link javax.swing.DefaultComboBoxModel#removeAllElements() Removes all items} 097 * and {@link ComboBoxHistory#addElement(String) adds} the given items. 098 * @param items the items to set 099 */ 100 public void setItemsAsString(List<String> items) { 101 removeAllElements(); 102 for (int i = items.size()-1; i >= 0; i--) { 103 addElement(items.get(i)); 104 } 105 } 106 107 /** 108 * Returns the {@link AutoCompletionListItem} items as strings 109 * @return a list of strings 110 */ 111 public List<String> asStringList() { 112 List<String> list = new ArrayList<>(maxSize); 113 for (AutoCompletionListItem item : this) { 114 list.add(item.getValue()); 115 } 116 return list; 117 } 118 119 public void addHistoryChangedListener(HistoryChangedListener l) { 120 listeners.add(l); 121 } 122 123 public void removeHistoryChangedListener(HistoryChangedListener l) { 124 listeners.remove(l); 125 } 126 127 private void fireHistoryChanged() { 128 for (HistoryChangedListener l : listeners) { 129 l.historyChanged(asStringList()); 130 } 131 } 132}