Java tutorial
/* @VaadinApache2LicenseForJavaFiles@ */ package com.vaadin.terminal.gwt.client.ui; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.DomEvent.Type; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Container; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.RenderSpace; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; public class VAbsoluteLayout extends ComplexPanel implements Container { /** Tag name for widget creation */ public static final String TAGNAME = "absolutelayout"; /** Class name, prefix in styling */ public static final String CLASSNAME = "v-absolutelayout"; private DivElement marginElement; protected final Element canvas = DOM.createDiv(); // private int excessPixelsHorizontal; // // private int excessPixelsVertical; private Object previousStyleName; private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>(); protected ApplicationConnection client; private boolean rendering; private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(this, EventId.LAYOUT_CLICK) { @Override protected Paintable getChildComponent(Element element) { return getComponent(element); } @Override protected <H extends EventHandler> HandlerRegistration registerHandler(H handler, Type<H> type) { return addDomHandler(handler, type); } }; public VAbsoluteLayout() { setElement(Document.get().createDivElement()); setStyleName(CLASSNAME); marginElement = Document.get().createDivElement(); canvas.getStyle().setProperty("position", "relative"); canvas.getStyle().setProperty("overflow", "hidden"); marginElement.appendChild(canvas); getElement().appendChild(marginElement); } public RenderSpace getAllocatedSpace(Widget child) { // TODO needs some special handling for components with only on edge // horizontally or vertically defined AbsoluteWrapper wrapper = (AbsoluteWrapper) child.getParent(); int w; if (wrapper.left != null && wrapper.right != null) { w = wrapper.getOffsetWidth(); } else if (wrapper.right != null) { // left == null // available width == right edge == offsetleft + width w = wrapper.getOffsetWidth() + wrapper.getElement().getOffsetLeft(); } else { // left != null && right == null || left == null && // right == null // available width == canvas width - offset left w = canvas.getOffsetWidth() - wrapper.getElement().getOffsetLeft(); } int h; if (wrapper.top != null && wrapper.bottom != null) { h = wrapper.getOffsetHeight(); } else if (wrapper.bottom != null) { // top not defined, available space 0... bottom of wrapper h = wrapper.getElement().getOffsetTop() + wrapper.getOffsetHeight(); } else { // top defined or both undefined, available space == canvas - top h = canvas.getOffsetHeight() - wrapper.getElement().getOffsetTop(); } return new RenderSpace(w, h); } public boolean hasChildComponent(Widget component) { for (Iterator<Entry<String, AbsoluteWrapper>> iterator = pidToComponentWrappper.entrySet() .iterator(); iterator.hasNext();) { if (iterator.next().getValue().paintable == component) { return true; } } return false; } public void replaceChildComponent(Widget oldComponent, Widget newComponent) { for (Widget wrapper : getChildren()) { AbsoluteWrapper w = (AbsoluteWrapper) wrapper; if (w.getWidget() == oldComponent) { w.setWidget(newComponent); return; } } } public boolean requestLayout(Set<Paintable> children) { // component inside an absolute panel never affects parent nor the // layout return true; } public void updateCaption(Paintable component, UIDL uidl) { AbsoluteWrapper parent2 = (AbsoluteWrapper) ((Widget) component).getParent(); parent2.updateCaption(uidl); } public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { rendering = true; this.client = client; // TODO margin handling if (client.updateComponent(this, uidl, true)) { rendering = false; return; } clickEventHandler.handleEventHandlerRegistration(client); HashSet<String> unrenderedPids = new HashSet<String>(pidToComponentWrappper.keySet()); for (Iterator<Object> childIterator = uidl.getChildIterator(); childIterator.hasNext();) { UIDL cc = (UIDL) childIterator.next(); if (cc.getTag().equals("cc")) { UIDL componentUIDL = cc.getChildUIDL(0); unrenderedPids.remove(componentUIDL.getId()); getWrapper(client, componentUIDL).updateFromUIDL(cc); } } for (String pid : unrenderedPids) { AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid); pidToComponentWrappper.remove(pid); absoluteWrapper.destroy(); } rendering = false; } private AbsoluteWrapper getWrapper(ApplicationConnection client, UIDL componentUIDL) { AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL.getId()); if (wrapper == null) { wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL)); pidToComponentWrappper.put(componentUIDL.getId(), wrapper); add(wrapper); } return wrapper; } @Override public void add(Widget child) { super.add(child, canvas); } @Override public void setStyleName(String style) { super.setStyleName(style); if (previousStyleName == null || !previousStyleName.equals(style)) { // excessPixelsHorizontal = -1; // excessPixelsVertical = -1; } } @Override public void setWidth(String width) { super.setWidth(width); // TODO do this so that canvas gets the sized properly (the area // inside marginals) canvas.getStyle().setProperty("width", width); if (!rendering) { relayoutRelativeChildren(); } } private void relayoutRelativeChildren() { for (Widget widget : getChildren()) { if (widget instanceof AbsoluteWrapper) { AbsoluteWrapper w = (AbsoluteWrapper) widget; client.handleComponentRelativeSize(w.getWidget()); w.updateCaptionPosition(); } } } @Override public void setHeight(String height) { super.setHeight(height); // TODO do this so that canvas gets the sized properly (the area // inside marginals) canvas.getStyle().setProperty("height", height); if (!rendering) { relayoutRelativeChildren(); } } public class AbsoluteWrapper extends SimplePanel { private String css; private String left; private String top; private String right; private String bottom; private String zIndex; private Paintable paintable; private VCaption caption; public AbsoluteWrapper(Paintable paintable) { this.paintable = paintable; setStyleName(CLASSNAME + "-wrapper"); } public void updateCaption(UIDL uidl) { boolean captionIsNeeded = VCaption.isNeeded(uidl); if (captionIsNeeded) { if (caption == null) { caption = new VCaption(paintable, client); VAbsoluteLayout.this.add(caption); } caption.updateCaption(uidl); updateCaptionPosition(); } else { if (caption != null) { caption.removeFromParent(); caption = null; } } } @Override public void setWidget(Widget w) { // this fixes #5457 (Widget implementation can change on-the-fly) paintable = (Paintable) w; super.setWidget(w); } public void destroy() { if (caption != null) { caption.removeFromParent(); } client.unregisterPaintable(paintable); removeFromParent(); } public void updateFromUIDL(UIDL componentUIDL) { setPosition(componentUIDL.getStringAttribute("css")); if (getWidget() != paintable) { setWidget((Widget) paintable); } UIDL childUIDL = componentUIDL.getChildUIDL(0); paintable.updateFromUIDL(childUIDL, client); if (childUIDL.hasAttribute("cached")) { // child may need relative size adjustment if wrapper details // have changed this could be optimized (check if wrapper size // has changed) client.handleComponentRelativeSize((Widget) paintable); } } public void setPosition(String stringAttribute) { if (css == null || !css.equals(stringAttribute)) { css = stringAttribute; top = right = bottom = left = zIndex = null; if (!css.equals("")) { String[] properties = css.split(";"); for (int i = 0; i < properties.length; i++) { String[] keyValue = properties[i].split(":"); if (keyValue[0].equals("left")) { left = keyValue[1]; } else if (keyValue[0].equals("top")) { top = keyValue[1]; } else if (keyValue[0].equals("right")) { right = keyValue[1]; } else if (keyValue[0].equals("bottom")) { bottom = keyValue[1]; } else if (keyValue[0].equals("z-index")) { zIndex = keyValue[1]; } } } // ensure ne values Style style = getElement().getStyle(); /* * IE8 dies when nulling zIndex, even in IE7 mode. All other css * properties (and even in older IE's) accept null values just * fine. Assign empty string instead of null. */ if (zIndex != null) { style.setProperty("zIndex", zIndex); } else { style.setProperty("zIndex", ""); } style.setProperty("top", top); style.setProperty("left", left); style.setProperty("right", right); style.setProperty("bottom", bottom); } updateCaptionPosition(); } private void updateCaptionPosition() { if (caption != null) { Style style = caption.getElement().getStyle(); style.setProperty("position", "absolute"); style.setPropertyPx("left", getElement().getOffsetLeft()); style.setPropertyPx("top", getElement().getOffsetTop() - caption.getHeight()); } } } /** * Returns the deepest nested child component which contains "element". The * child component is also returned if "element" is part of its caption. * * @param element * An element that is a nested sub element of the root element in * this layout * @return The Paintable which the element is a part of. Null if the element * belongs to the layout and not to a child. */ private Paintable getComponent(Element element) { return Util.getPaintableForElement(client, this, element); } }