package org.ovirt.engine.ui.common.widget;
import java.util.Iterator;
import java.util.NoSuchElementException;
import com.google.gwt.user.client.ui.HasOneWidget;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
/**
* Decorates a {@link Widget}.
* <p>
* {@code WidgetDecorator} implements {@link IsWidget#asWidget asWidget}
* by returning the decorated widget itself. This means the decorator is
* transparent to GWT Widget parent/child hierarchy, and thus transparent
* to physical DOM element hierarchy.
* <p>
* For example, the following UiBinder template:
*
* <pre>
* <FlowPanel>
* <WidgetDecorator>
* <Button/>
* </WidgetDecorator>
* </FlowPanel>
* </pre>
*
* renders into the following HTML markup:
*
* <pre>
* <div> <!-- FlowPanel -->
* <button/> <!-- Button -->
* </div>
* </pre>
*
* <p>
* This effectively allows implementing the "decorator" design pattern:
* implement {@link #decorateWidget} and apply desired functionality to
* the decorated widget.
*/
public abstract class WidgetDecorator implements IsWidget, HasWidgets, HasOneWidget {
private Widget widget;
public WidgetDecorator() {
}
public WidgetDecorator(Widget w) {
setWidget(w);
}
@Override
public Widget asWidget() {
return widget;
}
@Override
public Widget getWidget() {
return asWidget();
}
@Override
public void setWidget(Widget w) {
// Validate.
if (w == widget) {
return;
}
// Detach new child.
if (w != null) {
w.removeFromParent();
}
// Remove old child.
if (widget != null) {
remove(widget);
}
// Logical attach.
widget = w;
// Decorator hook.
if (widget != null) {
decorateWidget(widget);
}
}
protected abstract void decorateWidget(Widget w);
@Override
public void setWidget(IsWidget w) {
setWidget(w.asWidget());
}
@Override
public void add(Widget w) {
if (getWidget() != null) {
throw new IllegalStateException("Can only contain one child widget"); //$NON-NLS-1$
}
setWidget(w);
}
@Override
public boolean remove(Widget w) {
// Validate.
if (w != widget) {
return false;
}
// Logical detach.
clear();
return true;
}
@Override
public void clear() {
setWidget(null);
}
@Override
public Iterator<Widget> iterator() {
// Simple iterator for the single widget.
return new Iterator<Widget>() {
boolean hasElement = widget != null;
Widget returned = null;
@Override
public boolean hasNext() {
return hasElement;
}
@Override
public Widget next() {
if (!hasElement || (widget == null)) {
throw new NoSuchElementException();
}
hasElement = false;
returned = widget;
return returned;
}
@Override
public void remove() {
if (returned != null) {
WidgetDecorator.this.remove(returned);
}
}
};
}
}