/*******************************************************************************
* Copyright (c) 2016
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.graphics.utils;
import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;
/**
* This class manages a timer that is called every second to update the UI contents.
*
* @author Michael Zangl
* @param <T>
* The data type that backs this UI element. Should be immutable.
*/
public class UIUpdater<T> {
private static final int UPDATER_INTERVALL = 1000;
/**
* A listener that listens to UI update events.
*
* @author Michael Zangl
*
* @param <T>
* The data type that is updated. Should be immutable.
*/
public interface IUpdateReceiver<T> {
/**
* Called when an update to the UI is required.
*
* @param data
* The data to update with.
*/
void uiUpdate(T data);
}
/**
* A data provider that provides the data that might have updated.
*
* @author Michael Zangl
*
* @param <T>
* The data type. Should be immutable.
*/
public interface IDataProvider<T> {
/**
* Gets the current data state.
*
* @return The state.
*/
T getCurrentUIData();
}
private static Timer timer;
private TimerTask started;
private IDataProvider<T> dataProvider;
private Collection<? extends IUpdateReceiver<T>> receivers;
private T lastData;
/**
* Creates a new updater.
*
* @param dataProvider
* The data provider to check for.
* @param receivers
* The receivers to notify on data changes.
*/
public UIUpdater(IDataProvider<T> dataProvider, Collection<? extends IUpdateReceiver<T>> receivers) {
this.dataProvider = dataProvider;
this.receivers = receivers;
}
/**
* Starts the updater thread.
*
* @param sendNow
* <code>true</code> if we should fire an update now.
*/
public synchronized void start(boolean sendNow) {
if (started != null) {
throw new IllegalStateException("UI updater already started.");
}
if (sendNow) {
updateState();
}
started = new TimerTask() {
@Override
public void run() {
updateState();
}
};
getUITimer().scheduleAtFixedRate(started, 0, UPDATER_INTERVALL);
}
/**
* Stops the {@link UIUpdater}.
*/
public synchronized void stop() {
if (started == null) {
throw new IllegalStateException("UI updater already stopped.");
}
started.cancel();
started = null;
}
/**
* Sends a state update.
*/
protected synchronized void updateState() {
T data = dataProvider.getCurrentUIData();
if (data == null) {
throw new NullPointerException(dataProvider + " returned null.");
}
if (lastData == null || !data.equals(lastData)) {
for (IUpdateReceiver<T> r : receivers) {
r.uiUpdate(data);
}
lastData = data;
}
}
private static synchronized Timer getUITimer() {
if (timer == null) {
timer = new Timer();
}
return timer;
}
/**
* Creates a new updater.
*
* @param dataProvider
* The data provider to check for.
* @param receivers
* The receivers to notify on data changes.
* @param <T>
* The data type that backs this UI element. Should be immutable.
* @return The updater.
*/
public static <T> UIUpdater<T> getUpdater(IDataProvider<T> dataProvider, Collection<? extends IUpdateReceiver<T>> receivers) {
return new UIUpdater<T>(dataProvider, receivers);
}
/**
* Forces an immediate update.
*/
public void forceUpdate() {
updateState();
}
}