package org.geogebra.desktop.gui.view;
import java.awt.event.ActionListener;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.Timer;
import org.geogebra.common.kernel.geos.GProperty;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.desktop.gui.view.algebra.AlgebraControllerD;
import org.geogebra.desktop.gui.view.algebra.AlgebraViewD;
/**
* This class will collect update events in a time slice and bundles them in a
* Set and after the time slice it will handle them to its attached view.
* (Multiple updates of the same GeoElement in a time slice are only handled
* down to the extends AlgebraView once at the end of the time slice.)
*
* @author Lucas Binter
*/
public class CompressedAlgebraView extends AlgebraViewD
implements CompressedView {
private static final long serialVersionUID = 6383245533545749844L;
private int ups;
private Timer updateTimer;
private Set<GeoElement> updateSet;
private ActionListener updateListener;
private final ReentrantLock lock = new ReentrantLock();
private int rps;
private Timer repaintTimer;
private ActionListener repaintListener;
private boolean needRepaint;
/**
* @param algCtrl
* the Algebra Controller for the extended AlgebraView
* @param updatesPerSecond
* the updates per second handled down to the extended
* AlgebraView
*/
public CompressedAlgebraView(AlgebraControllerD algCtrl,
int updatesPerSecond) {
this(algCtrl, updatesPerSecond, updatesPerSecond);
}
/**
* @param algCtrl
* the Algebra Controller for the extended AlgebraView
* @param updatesPerSecond
* the updates per second handled down to the extended
* AlgebraView
* @param repaintsPerSecond
* the maximum repaints per second rate
*/
public CompressedAlgebraView(AlgebraControllerD algCtrl,
int updatesPerSecond, int repaintsPerSecond) {
super(algCtrl);
ups = updatesPerSecond;
rps = repaintsPerSecond;
updateTimer = new Timer(1000 / ups, null);
updateTimer.setRepeats(false);
repaintTimer = new Timer(1000 / rps, null);
repaintTimer.setRepeats(false);
updateSet = new HashSet<GeoElement>();
updateListener = new CompressedUpdateListener(this, updateTimer,
updateSet, lock);
updateTimer.addActionListener(updateListener);
repaintListener = new CompressedRepaintListener(this);
repaintTimer.addActionListener(repaintListener);
needRepaint = false;
}
@Override
final public void update(GeoElement geo) {
if (updateTimer.isRunning()) {
lock.lock();
try {
updateSet.add(geo);
} finally {
lock.unlock();
}
} else {
updateTimer.start();
updateNow(geo);
}
}
@Override
public void updateNow(GeoElement geo) {
super.update(geo);
}
@Override
final public void updateVisualStyle(GeoElement geo, GProperty prop) {
update(geo);
}
@Override
final public void repaintView() {
repaint();
}
@Override
final public void repaintNow() {
if (needRepaint) {
super.repaint();
}
needRepaint = false;
}
@Override
final public void repaint() {
if (repaintTimer == null) {
// needed because of null pointer error (Constructor)
repaintNow();
return;
}
if (repaintTimer.isRunning()) {
needRepaint = true;
} else {
repaintTimer.start();
needRepaint = true;
repaintNow();
}
}
}