package org.vaadin.smartgwt.server;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Set;
import com.vaadin.terminal.Paintable;
/**
* <p>
* This class contains the logic necessary for those UI components which needs to perform partial server-client updates. The component needs to have this as a
* private field and implement calls at key points (see all methods' javadocs).
* </p>
* <p>
* Creditation: the main idea is obtained from http://code.google.com/p/vopenlayers/source/browse/trunk/src/main/java/org/vaadin/vol/OpenLayersMap.java
* </p>
*
* @since 0.2.9
* @author ttran at coolersport.info
**/
public class PartialPaintChecker implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private HashMap<String, Boolean> flags = new HashMap<String, Boolean>();
private boolean partialRepaint = true;
private boolean fullRepaint = true;
private Paintable p;
private static boolean forcedFullRepaint = false;
public static void forceFullRepaint()
{
forcedFullRepaint = true;
}
public static void resetFullRepaint()
{
forcedFullRepaint = false;
}
public Set<String> getFlagged()
{
return flags.keySet();
}
/**
* <p>
* Construct the checker only for this paintable.
* </p>
*
* @param paintable
* dedicated paintable
**/
public PartialPaintChecker(final Paintable paintable)
{
p = paintable;
}
/**
* <p>
* Check if a partial repaint is needed instead of full repaint.
* </p>
*
* @return false if full repaint is required or no flag was marked as dirty, true otherwise
**/
public boolean isPartialRepaint()
{
if (fullRepaint || forcedFullRepaint)
return false;
return flags.size() > 0;
}
/**
* <p>
* Check if a full repaint is needed.
* </p>
*
* @return true if full repaint is required
**/
public boolean isFullRepaint()
{
return fullRepaint || forcedFullRepaint;
}
/**
* <p>
* This method is meant to be called inside overridden paintContent() method to determine if a flag is marked as dirty to send relevant update to client.
* Developer can rely on this method to decide when to send updates for relevant data.
* </p>
*
* @param flag
* flag to check
* @return false if the flag was not marked as dirty, true otherwise (i.e. full repaint is needed or no flag was marked as dirty)
**/
public boolean isDirty(final String flag)
{
return (fullRepaint || forcedFullRepaint || flags.containsKey(flag));
}
/**
* <p>
* Indicate if a flag is dirty and needs to do a partial repaint. If a full repaint is not in progress, {@link #partialPaint()} will be triggered and
* eventually call {@link Paintable#requestRepaint()}.
* </p>
* <p>
* Developer may explicitly call {@link Paintable#requestRepaint()} after calling this method to enforce a full repaint.
* </p>
*
* @param flag
* flag to set as dirty, flags are stored using bit-comparison so ensure its value is a binary-bit like: 1, 2, 4, 8, 16, 32, and so on
**/
public void setDirty(final String attribute)
{
if (!fullRepaint)
{
flags.put(attribute, true);
partialPaint();
}
}
/**
* <p>
* The paintable must override paintContent() method and call this method at very end of the method.
* </p>
**/
public void paintContentPerformed()
{
clearDirtyFlags();
fullRepaint = false;
}
/**
* <p>
* The paintable must override {@link Paintable#requestRepaint()} method and call this method at very beginning of the method.
* </p>
**/
public void checkBeforeRequestRepaint()
{
if (!partialRepaint)
{
clearDirtyFlags();
fullRepaint = true;
}
}
private void clearDirtyFlags()
{
flags.clear();
}
private void partialPaint()
{
partialRepaint = true;
try
{
p.requestRepaint();
}
finally
{
partialRepaint = false;
}
}
}