package org.aperteworkflow.widgets.refresherwrapper;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import org.aperteworkflow.widgets.refresherwrapper.widgetset.client.ui.VRefresherWrapper;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.AbstractComponentContainer;
import com.vaadin.ui.ClientWidget;
import com.vaadin.ui.Component;
/**
* Based on LazyLoadWrapper by Petri Heinonen
*
* https://vaadin.com/directory/#addon/lazyloadwrapper
*
*
*
* Server side component for the VLazyLoadingWrapper widget.
*
* A wrapper for loading Vaadin components lazily. The wrapper creates a
* lightweight placeholder on the client side that has a spinner on it until the
* user has scrolled the placeholder in to view at which point the wrapper will
* draw the lazy load component. <br />
* <br />
*
* The component that is to be lazily loaded can be provided to the Lazy load
* wrapper (LLW), through:
* <ul>
* <li>one of the constructors</li>
* <li>the {@link RefresherWrapper#setLazyLoadComponent(Component)} -method</li>
* <li>or the {@link LazyLoadComponentProvider#onComponentVisible()} -interface.
* </li>
* </ul>
* If the lazy load component is has a defined width and/or height, the wrapper
* will try to set the size of the placeholder to the size of the child
* component automatically. If no sizing information is available, the wrapper
* will set the (undefined size) for placeholder to a default value of of 100px <br />
* <br />
* The LLW has a proximity parameter that can be set through
* {@link #setProximity(int)}. This works as a "fine tune" for the loading
* event. The proximity is the offset from the visible area when the lazy load
* component should be loaded from the server.<br />
* * Positive numbers = before actually visible <br />
* * Negative numbers = must be <i>X<i/> px visible <br />
* * <b>Default: </b> 250px <br />
* <br />
*
* LLW can also be set to use a delay timer that defines a delay how long the
* placeholder should be visible before the child component is drawn. <br>
* * <b>Default: </b> 0 ms. <br>
* <br>
*/
@SuppressWarnings("serial")
@ClientWidget(VRefresherWrapper.class)
public class RefresherWrapper extends AbstractComponentContainer {
private Component lazyloadComponent = null;
private boolean autoReinitLazyLoad = false;
/**
* Defines if the container of the lazy load wrapper should be static or
* not. If false, the container will expand to fit the child component,
* while if true, the container will keep it's size and force the child to
* be drawn within the size defined by the placeholder.
*/
private boolean staticContainer = false;
/**
* The instance of {@link LazyLoadComponentProvider} that will provide the
* child component when it's needed (server side lazy load).
*/
private LazyLoadComponentProvider childProvider = null;
private String placeholderHeight = "100px";
private String placeholderWidth = "100px";
private Integer refreshIntervalMs = 5000;
/**
* Create new Lazy load wrapper with default settings and no component.
*/
public RefresherWrapper() {
super();
}
/* CONSTRUCTORS FOR SERVER SIDE LAZY LOAD */
/**
* Create a lazy load wrapper with default settings and server side lazy
* load.
*
* @param childProvider
* - the instance of {@link LazyLoadComponentProvider} that will
* provide the <i>component</i> when it's needed.
*/
public RefresherWrapper(LazyLoadComponentProvider childProvider) {
super();
this.childProvider = childProvider;
}
/**
* Create a lazy load wrapper with a defined
* {@link RefresherWrapper#proximity} and server side lazy load.
*
* @param proximity
* - the proximity in pixels from the viewable area when the
* component should be loaded
* @param childProvider
* - the instance of {@link LazyLoadComponentProvider} that will
* provide the <i>component</i> when it's needed.
*/
public RefresherWrapper(int refreshIntervalMs, LazyLoadComponentProvider childProvider) {
this(childProvider);
this.refreshIntervalMs = refreshIntervalMs;
}
/**
* Create a new lazy load wrapper with server side lazy load and with a
* specified placeholder size that resizes itself to fit the child
* components when they are loaded.
*
* @param placeHolderWidth
* - the width of the placeholder
* @param placeHolderHeight
* - the height of the placeholder
* @param childProvider
* - the instance of {@link LazyLoadComponentProvider} that will
* provide the <i>component</i> when it's needed.
*/
public RefresherWrapper(String placeHolderWidth, String placeHolderHeight, int refreshIntervalMs, LazyLoadComponentProvider childProvider) {
this(childProvider);
setPlaceHolderSize(placeHolderWidth, placeHolderHeight);
}
/**
* Create a new lazy load wrapper with server side lazy load and with a
* specified placeholder size that does/does not resize itself when the
* child components are loaded.
*
* @param placeHolderWidth
* - the width of the placeholder
* @param placeHolderHeight
* - the height of the placeholder
* @param staticContainer
* - true if the placeholder should keep it size after that the
* components are loaded <br />
* false if the placeholder should auto resize to accommodate
* is's children.
* @param childProvider
* - the instance of {@link LazyLoadComponentProvider} that will
* provide the <i>component</i> when it's needed.
*/
public RefresherWrapper(String placeHolderWidth, String placeHolderHeight, boolean staticContainer, int refreshIntervalMs,
LazyLoadComponentProvider childProvider) {
this(placeHolderWidth, placeHolderHeight, refreshIntervalMs, childProvider);
setStaticConatiner(staticContainer);
}
/*
* Methods
*/
/**
* @deprecated Use {@link #setLazyLoadComponent(Component)} instead.
*/
@Override
@Deprecated
public void addComponent(Component component) {
throw new UnsupportedOperationException();
}
/*
*
* Getters and setters
*/
/**
* Set the size of the place holder that will be shown on the client-side.
*
* @param width
* @param height
*/
public void setPlaceHolderSize(String width, String height) {
placeholderHeight = height;
placeholderWidth = width;
if (staticContainer) {
setWidth(width);
setHeight(height);
} else {
setSizeUndefined();
}
requestRepaint();
}
/**
* Sets the static container. If static container is set to true, the
* container will keep it's size when the lazy load component is loaded. <br/>
* <br/>
* If static container is set to false, the wrapper will try to
* expand/shrink to fit it's child component.
*
* @param staticContainer
*/
public void setStaticConatiner(boolean staticContainer) {
this.staticContainer = staticContainer;
if (staticContainer) {
setWidth(placeholderWidth);
setHeight(placeholderHeight);
} else {
setSizeUndefined();
}
requestRepaint();
}
/**
* Get the current container mode.
*/
public boolean getStaticContainer() {
return staticContainer;
}
/**
* Set the isVisible parameter for the wrapper. When called with <i>true</i>
* this will show the wrapped component immediately on the client side. <br>
* <br>
* <i> Note: not the same thing as Vaadins isVisible()</i><br>
*
*
* @param visible
* <br>
* - true: show wrapped component immediately <br>
* - false: show child component when scrolled into view.
*/
public void reloadComponent() {
if (childProvider != null) {
lazyloadComponent = childProvider.onComponentVisible();
}
// Attach child to container.
if (lazyloadComponent != null) {
super.addComponent(lazyloadComponent);
}
requestRepaint();
}
/*
* Server to Client communication
*/
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
target.addAttribute(VRefresherWrapper.PLACEHOLDER_HEIGHT, placeholderHeight);
target.addAttribute(VRefresherWrapper.PLACEHOLDER_WIDTH, placeholderWidth);
target.addAttribute(VRefresherWrapper.STATIC_CONTAINER, staticContainer);
target.addAttribute(VRefresherWrapper.WRAPPER_AUTOREINIT_ON_REATTACH, autoReinitLazyLoad);
target.addAttribute(VRefresherWrapper.REFRESH_INTERVAL, refreshIntervalMs);
if (lazyloadComponent != null) {
lazyloadComponent.paint(target);
}
}
/**
* Receive and handle events and other variable changes from the client.
*
* {@inheritDoc}
*/
@Override
public void changeVariables(Object source, Map<String, Object> variables) {
super.changeVariables(source, variables);
if (variables.containsKey(VRefresherWrapper.WIDGET_VISIBLE_ID)) {
reloadComponent();
}
}
public Iterator<Component> getComponentIterator() {
Iterator<Component> iterator = new Iterator<Component>() {
private boolean first = lazyloadComponent == null;
public boolean hasNext() {
return !first;
}
public Component next() {
if (!first) {
first = true;
return lazyloadComponent;
} else {
return null;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
return iterator;
}
public void replaceComponent(Component oldComponent, Component newComponent) {
throw new UnsupportedOperationException();
}
/*
*
* Server side lazy load...
*/
public void setAutoReinitLazyLoad(boolean autoReinitLazyLoad) {
this.autoReinitLazyLoad = autoReinitLazyLoad;
}
public boolean isAutoReinitLazyLoad() {
return autoReinitLazyLoad;
}
/**
* The listener interface for implementing server side lazy load. If no
* child component is specified for the lazy load wrapper, the wrapper will
* try to retrieve one using this interface when the placeholder on the
* client side is visible.
*
*/
public interface LazyLoadComponentProvider extends Serializable {
/**
* Called when the placeholder component has become visible
*/
public Component onComponentVisible();
}
/**
* Get the delay that the placeholder is visible on client side before the
* lazy load component is actually loaded.
*
* @return placeholderVisibleDelay - the delay in ms
*/
public int getRefreshIntervalMs() {
return refreshIntervalMs;
}
/**
* Set the delay how long the placeholder should be visible before the
* component is loaded from the server to the client.
*
* @param placeholderVisibleDelay
* - the delay in ms
*/
public void setRefreshIntervalMs(int refreshIntervalMs) {
this.refreshIntervalMs = refreshIntervalMs;
requestRepaint();
}
}