001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.util.AbstractCollection; 005import java.util.Iterator; 006import java.util.List; 007 008/** 009 * This is a proxy of a collection that notifies a listener on every collection change 010 * @author Michael Zangl 011 * 012 * @param <T> The entry type 013 * @since 12267 (extracted from GpxData) 014 * @since 12156 015 */ 016public class ListeningCollection<T> extends AbstractCollection<T> { 017 private final List<T> base; 018 private final Runnable runOnModification; 019 020 /** 021 * Constructs a new {@code ListeningCollection}. 022 * @param base base collection 023 * @param runOnModification runnable run at each modification 024 * @since 12269 025 */ 026 public ListeningCollection(List<T> base, Runnable runOnModification) { 027 this.base = base; 028 this.runOnModification = runOnModification; 029 } 030 031 @Override 032 public final Iterator<T> iterator() { 033 Iterator<T> it = base.iterator(); 034 return new Iterator<T>() { 035 private T object; 036 037 @Override 038 public boolean hasNext() { 039 return it.hasNext(); 040 } 041 042 @Override 043 public T next() { 044 object = it.next(); 045 return object; 046 } 047 048 @Override 049 public void remove() { 050 if (object != null) { 051 removed(object); 052 object = null; 053 } 054 it.remove(); 055 } 056 }; 057 } 058 059 @Override 060 public final int size() { 061 return base.size(); 062 } 063 064 @Override 065 @SuppressWarnings("unchecked") 066 public final boolean remove(Object o) { 067 boolean remove = base.remove(o); 068 if (remove) { 069 removed((T) o); 070 } 071 return remove; 072 } 073 074 @Override 075 public final boolean add(T e) { 076 boolean add = base.add(e); 077 added(e); 078 return add; 079 } 080 081 /** 082 * Called when an object is removed. 083 * @param object the removed object 084 */ 085 protected void removed(T object) { 086 runOnModification.run(); 087 } 088 089 /** 090 * Called when an object is added. 091 * @param object the added object 092 */ 093 protected void added(T object) { 094 runOnModification.run(); 095 } 096}