org.aksw.commons.collection.observable.ObservableCollectionOps Maven / Gradle / Ivy
package org.aksw.commons.collection.observable;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeSupport;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Sets;
public class ObservableCollectionOps {
/**
* Updates the 'backend' collection by first performing removals followed by additions.
*
* @param
* @param self
* @param backend
* @param vcs
* @param pcs
* @param clearIntersection Whether to adept additions and removals for an empty intersection
* @param rawAdditions
* @param rawRemovals
* @return
*/
public static boolean applyDeltaSet(
Collection self,
Set backend,
VetoableChangeSupport vcs,
PropertyChangeSupport pcs,
boolean clearIntersection,
Collection extends T> rawAdditions, Collection> rawRemovals) {
// Set up the physical removals / additions that will be sent to the backend
// This may include overlapping items
@SuppressWarnings("unchecked")
Set physRemovals = rawRemovals == self
? rawRemovals.stream().map(x -> (T)x).collect(Collectors.toCollection(LinkedHashSet::new))
: rawRemovals.stream().filter(backend::contains).map(x -> (T)x).collect(Collectors.toCollection(LinkedHashSet::new));
Set physAdditions = rawAdditions.stream()
.filter(x -> !backend.contains(x) || physRemovals.contains(x))
.collect(Collectors.toCollection(LinkedHashSet::new));
Set intersection = new LinkedHashSet<>(Sets.intersection(physAdditions, physRemovals));
Set as;
Set rs;
if (clearIntersection || intersection.isEmpty()) {
physRemovals.removeAll(intersection);
physAdditions.removeAll(intersection);
as = physAdditions;
rs = physRemovals;
} else {
// Set up the change sets
as = new LinkedHashSet<>(physAdditions);
rs = new LinkedHashSet<>(physRemovals);
as.removeAll(intersection);
rs.removeAll(intersection);
}
// FIXME additions and removals may have common items! those should be removed in
// the event's additions / removals sets
boolean result = false;
{
Collection oldValue = self;
Collection newValue = rawRemovals == self
? physAdditions
: Sets.union(Sets.difference(backend, rs), as);
try {
vcs.fireVetoableChange(new CollectionChangedEventImpl<>(
self, oldValue, newValue,
as, rs, Collections.emptySet()));
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
boolean changeByRemoval;
if (rawRemovals == self) {
changeByRemoval = !backend.isEmpty();
if (changeByRemoval) {
// Only invoke clear if we have to; prevent triggering anything
backend.clear();
}
} else {
changeByRemoval = backend.removeAll(physRemovals);
}
boolean changeByAddition = backend.addAll(physAdditions);
result = changeByRemoval || changeByAddition;
{
Collection oldValue = rawRemovals == self
? physRemovals
: Sets.union(Sets.difference(backend, as), rs);
Collection newValue = self;
pcs.firePropertyChange(new CollectionChangedEventImpl<>(
self, oldValue, newValue,
as, rs, Collections.emptySet()));
}
return result;
}
//
// public static boolean applyDelta(
// Collection self,
// Collection backend,
// VetoableChangeSupport vcs,
// PropertyChangeSupport pcs,
// boolean duplicateAware,
// Collection extends T> rawAdditions, Collection> rawRemovals) {
//
// // Set up the physical removals / additions that will be sent to the backend
// // This may include overlapping items
// @SuppressWarnings("unchecked")
// Collection physRemovals = rawRemovals == self
// ? StreamOps.collect(duplicateAware, rawRemovals.stream().map(x -> (T)x))
// : StreamOps.collect(duplicateAware, rawRemovals.stream().filter(backend::contains).map(x -> (T)x));
// Collection physAdditions = StreamOps.collect(duplicateAware, rawAdditions.stream().filter(x -> !backend.contains(x) || physRemovals.contains(x)));
//
//
// // Set up the change sets -
// Set as = new LinkedHashSet<>(physAdditions);
// Set rs = new LinkedHashSet<>(physRemovals);
// Set intersection = new LinkedHashSet<>(Sets.intersection(as, rs));
//
// as.remove(intersection);
// rs.remove(intersection);
//
//
//
// // FIXME additions and removals may have common items! those should be removed in
// // the event's additions / removals sets
//
// boolean result = false;
//
// {
// Collection oldValue = self;
// Collection newValue = rawRemovals == self
// ? physAdditions
// : CollectionOps.smartUnion(CollectionOps.smartDifference(backend, physRemovals), physAdditions);
//
// try {
// vcs.fireVetoableChange(new CollectionChangedEventImpl<>(
// self, oldValue, newValue,
// as, rs, Collections.emptySet()));
// } catch (PropertyVetoException e) {
// throw new RuntimeException(e);
// }
// }
//
// boolean changeByRemoval;
// if (rawRemovals == self) {
// changeByRemoval = !backend.isEmpty();
// if (changeByRemoval) {
// // Only invoke clear if we have to; prevent triggering anything
// backend.clear();
// }
// } else {
// changeByRemoval = backend.removeAll(physRemovals);
// }
//
// boolean changeByAddition = backend.addAll(physAdditions);
// result = changeByRemoval || changeByAddition;
//
// {
// Collection oldValue = rawRemovals == self
// ? physRemovals
// : CollectionOps.smartUnion(CollectionOps.smartDifference(backend, physAdditions), physRemovals);
// Collection newValue = self;
//
// pcs.firePropertyChange(new CollectionChangedEventImpl<>(
// self, oldValue, newValue,
// as, rs, Collections.emptySet()));
// }
//
// return result;
// }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy