/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Matthew Hall - bug 262269
******************************************************************************/
package org.eclipse.core.internal.databinding.observable;
import java.util.Map;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.databinding.observable.IStaleListener;
import org.eclipse.core.databinding.observable.StaleEvent;
import org.eclipse.core.internal.databinding.identity.IdentityMap;
/**
* @since 1.0
*
*/
public class StalenessTracker {
private Map<IObservable, Boolean> staleMap = new IdentityMap<>();
private int staleCount = 0;
private final IStalenessConsumer stalenessConsumer;
private class ChildListener implements IStaleListener, IChangeListener {
@Override
public void handleChange(ChangeEvent event) {
processStalenessChange((IObservable) event.getSource(), true);
}
@Override
public void handleStale(StaleEvent event) {
processStalenessChange((IObservable) event.getSource(), true);
}
}
private ChildListener childListener = new ChildListener();
/**
* @param observables
* @param stalenessConsumer
*/
public StalenessTracker(IObservable[] observables,
IStalenessConsumer stalenessConsumer) {
this.stalenessConsumer = stalenessConsumer;
for (IObservable observable : observables) {
doAddObservable(observable, false);
}
stalenessConsumer.setStale(staleCount > 0);
}
/**
* @param child
* @param callback
*/
public void processStalenessChange(IObservable child, boolean callback) {
boolean oldStale = staleCount > 0;
boolean oldChildStale = getOldChildStale(child);
boolean newChildStale = child.isStale();
if (oldChildStale != newChildStale) {
if (oldChildStale) {
staleCount--;
} else {
staleCount++;
}
staleMap.put(child, newChildStale ? Boolean.TRUE : Boolean.FALSE);
}
boolean newStale = staleCount > 0;
if (callback && (newStale != oldStale)) {
stalenessConsumer.setStale(newStale);
}
}
/**
* @param child
*/
private boolean getOldChildStale(IObservable child) {
Boolean oldChildValue = staleMap.get(child);
boolean oldChildStale = oldChildValue != null && oldChildValue;
return oldChildStale;
}
/**
* @param observable
*/
public void addObservable(IObservable observable) {
doAddObservable(observable, true);
}
private void doAddObservable(IObservable observable, boolean callback) {
processStalenessChange(observable, callback);
observable.addChangeListener(childListener);
observable.addStaleListener(childListener);
}
/**
* @param observable
*/
public void removeObservable(IObservable observable) {
boolean oldStale = staleCount > 0;
boolean oldChildStale = getOldChildStale(observable);
if (oldChildStale) {
staleCount--;
}
staleMap.remove(observable);
observable.removeChangeListener(childListener);
observable.removeStaleListener(childListener);
boolean newStale = staleCount > 0;
if (newStale != oldStale) {
stalenessConsumer.setStale(newStale);
}
}
}