Browse Source

new component, absolutelayout (aka coordinatelayout #1267) and simple test case

svn changeset:7374/svn branch:6.0
tags/6.7.0.beta1
Matti Tahvonen 15 years ago
parent
commit
6175ddd0c1

+ 4
- 0
WebContent/ITMILL/themes/default/absolutelayout/absolutelayout.css View File

@@ -0,0 +1,4 @@
.i-absolutelayout-wrapper {
position: absolute;
overflow:hidden;
}

+ 6
- 0
WebContent/ITMILL/themes/default/styles.css View File

@@ -1,5 +1,11 @@
/* Automatically compiled css file from subdirectories. */

/* ./WebContent/ITMILL/themes/default/absolutelayout/absolutelayout.css */
.i-absolutelayout-wrapper {
position: absolute;
overflow:hidden;
}

/* ./WebContent/ITMILL/themes/default/accordion/accordion.css */
.i-accordion {
position: relative;

+ 12
- 0
WebContent/ITMILL/themes/tests-tickets/styles.css View File

@@ -1276,4 +1276,16 @@ padding:2px;
.i-button-nowraplink span {
white-space: normal;
}

.cyan {
background:cyan;
}
.yellow {
background:yellow;
}
.green {
background:green;
}

+ 5
- 0
src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java View File

@@ -5,6 +5,7 @@
package com.itmill.toolkit.terminal.gwt.client;

import com.google.gwt.user.client.ui.Widget;
import com.itmill.toolkit.terminal.gwt.client.ui.IAbsoluteLayout;
import com.itmill.toolkit.terminal.gwt.client.ui.IAccordion;
import com.itmill.toolkit.terminal.gwt.client.ui.IButton;
import com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox;
@@ -139,6 +140,8 @@ public class DefaultWidgetSet implements WidgetSet {
return new IPopupView();
} else if (IUriFragmentUtility.class == classType) {
return new IUriFragmentUtility();
} else if (IAbsoluteLayout.class == classType) {
return new IAbsoluteLayout();
}

return new IUnknownComponent();
@@ -249,6 +252,8 @@ public class DefaultWidgetSet implements WidgetSet {
return IPopupView.class;
} else if ("urifragment".equals(tag)) {
return IUriFragmentUtility.class;
} else if (IAbsoluteLayout.TAGNAME.equals(tag)) {
return IAbsoluteLayout.class;
}

return IUnknownComponent.class;

+ 320
- 0
src/com/itmill/toolkit/terminal/gwt/client/ui/IAbsoluteLayout.java View File

@@ -0,0 +1,320 @@
package com.itmill.toolkit.terminal.gwt.client.ui;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

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.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.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
import com.itmill.toolkit.terminal.gwt.client.BrowserInfo;
import com.itmill.toolkit.terminal.gwt.client.Container;
import com.itmill.toolkit.terminal.gwt.client.Paintable;
import com.itmill.toolkit.terminal.gwt.client.RenderSpace;
import com.itmill.toolkit.terminal.gwt.client.UIDL;

public class IAbsoluteLayout 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 = "i-absolutelayout";

private DivElement marginElement;

private Element canvas;

private int excessPixelsHorizontal;

private int excessPixelsVertical;

private Object previousStyleName;

private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>();

private ApplicationConnection client;

private boolean rendering;

public IAbsoluteLayout() {
setElement(Document.get().createDivElement());
setStyleName(CLASSNAME);
marginElement = Document.get().createDivElement();
canvas = DOM.createDiv();
canvas.getStyle().setProperty("position", "relative");
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) {
// TODO Auto-generated method stub

}

public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
rendering = true;
this.client = client;
// TODO margin handling
if (client.updateComponent(this, uidl, true)) {
rendering = false;
return;
}

HashSet<String> unrenderedPids = new HashSet<String>(
pidToComponentWrappper.keySet());

for (Iterator<UIDL> childIterator = uidl.getChildIterator(); childIterator
.hasNext();) {
UIDL cc = childIterator.next();
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 && BrowserInfo.get().isIE6()) {
relayoutWrappersForIe6();
}
}

@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 && BrowserInfo.get().isIE6()) {
relayoutWrappersForIe6();
}
}

private void relayoutWrappersForIe6() {
for (Widget wrapper : getChildren()) {
((AbsoluteWrapper) wrapper).ie6Layout();
}
}

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;

public AbsoluteWrapper(Paintable paintable) {
this.paintable = paintable;
setStyleName(CLASSNAME + "-wrapper");
}

public void destroy() {
client.unregisterPaintable(paintable);
removeFromParent();
}

public void updateFromUIDL(UIDL componentUIDL) {
setPosition(componentUIDL.getStringAttribute("css"));
if (getWidget() != paintable) {
setWidget((Widget) paintable);
}
paintable.updateFromUIDL(componentUIDL.getChildUIDL(0), client);
}

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();
style.setProperty("zIndex", zIndex);
style.setProperty("top", top);
style.setProperty("left", left);
style.setProperty("right", right);
style.setProperty("bottom", bottom);

if (BrowserInfo.get().isIE6()) {
ie6Layout();
}
}

}

private void ie6Layout() {
// special handling for IE6 is needed, it does not support
// setting both left/right or top/bottom
Style style = getElement().getStyle();
if (bottom != null && top != null) {
// define height for wrapper to simulate bottom property
int bottompixels = measureForIE6(bottom);
ApplicationConnection.getConsole().log("ALB" + bottompixels);
int height = canvas.getOffsetHeight() - bottompixels
- getElement().getOffsetTop();
ApplicationConnection.getConsole().log("ALB" + height);
if (height < 0) {
height = 0;
}
style.setPropertyPx("height", height);
} else {
// reset possibly existing value
style.setProperty("height", "");
}
if (left != null && right != null) {
// define width for wrapper to simulate right property
int rightPixels = measureForIE6(right);
ApplicationConnection.getConsole().log("ALR" + rightPixels);
int width = canvas.getOffsetWidth() - rightPixels
- getElement().getOffsetWidth();
ApplicationConnection.getConsole().log("ALR" + width);
if (width < 0) {
width = 0;
}
style.setPropertyPx("width", width);
} else {
// reset possibly existing value
style.setProperty("width", "");
}
}

}

private Element measureElement;

private int measureForIE6(String cssLength) {
if (measureElement == null) {
measureElement = DOM.createDiv();
measureElement.getStyle().setProperty("position", "absolute");
canvas.appendChild(measureElement);
}
measureElement.getStyle().setProperty("width", cssLength);
return measureElement.getOffsetWidth();
}

}

+ 54
- 0
src/com/itmill/toolkit/tests/layouts/TestAbsoluteLayout.java View File

@@ -0,0 +1,54 @@
package com.itmill.toolkit.tests.layouts;
import com.itmill.toolkit.tests.components.TestBase;
import com.itmill.toolkit.ui.AbsoluteLayout;
import com.itmill.toolkit.ui.Button;
import com.itmill.toolkit.ui.Label;
public class TestAbsoluteLayout extends TestBase {
@Override
protected String getDescription() {
return "This is absolute layout tester.";
}
@Override
protected Integer getTicketNumber() {
return null;
}
@Override
protected void setup() {
AbsoluteLayout layout = new AbsoluteLayout();
setTheme("tests-tickets");
layout.setStyleName("cyan");
layout.addComponent(new Label("Hello World"));
Button button = new Button("Centered button,z-index:10;");
button.setSizeFull();
layout.addComponent(button,
"top:40%;bottom:40%;right:20%;left:20%;z-index:10;");
Label label = new Label(
"Exotic positioned label. Fullsize, top:100px; left:2cm; right: 3.5in; bottom:12.12mm ");
label.setStyleName("yellow");
label.setSizeFull();
layout.addComponent(label,
"top:100px; left:2cm; right: 3.5in; bottom:12.12mm");
label = new Label("fullize, bottom:80%;left:80%;");
label.setStyleName("green");
label.setSizeFull();
layout.addComponent(label, "bottom:80%;left:80%;");
label = new Label("bottomright");
label.setSizeUndefined();
label.setStyleName("green");
layout.addComponent(label, "bottom:0px; right:0px;");
getLayout().setSizeFull();
getLayout().addComponent(layout);
}
}

+ 210
- 0
src/com/itmill/toolkit/ui/AbsoluteLayout.java View File

@@ -0,0 +1,210 @@
package com.itmill.toolkit.ui;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

import com.itmill.toolkit.terminal.PaintException;
import com.itmill.toolkit.terminal.PaintTarget;
import com.itmill.toolkit.terminal.gwt.client.ui.IAbsoluteLayout;

/**
* AbsoluteLayout is a layout implementation that mimics html absolute
* positioning.
*
*/
public class AbsoluteLayout extends AbstractLayout {

private Collection<Component> components = new HashSet<Component>();
private Map<Component, ComponentPosition> componentToCoordinates = new HashMap<Component, ComponentPosition>();

public AbsoluteLayout() {
setSizeFull();
}

@Override
public String getTag() {
return IAbsoluteLayout.TAGNAME;
}

public Iterator<Component> getComponentIterator() {
return components.iterator();
}

public void replaceComponent(Component oldComponent, Component newComponent) {
ComponentPosition position = getPosition(oldComponent);
removeComponent(oldComponent);
addComponent(newComponent);
componentToCoordinates.put(newComponent, position);
}

@Override
public void addComponent(Component c) {
components.add(c);
super.addComponent(c);
}

@Override
public void removeComponent(Component c) {
components.remove(c);
super.removeComponent(c);
}

public void addComponent(Component c, String cssPosition) {
addComponent(c);
getPosition(c).setCSSString(cssPosition);
}

public ComponentPosition getPosition(Component component) {
if (componentToCoordinates.containsKey(component)) {
return componentToCoordinates.get(component);
} else {
ComponentPosition coords = new ComponentPosition();
componentToCoordinates.put(component, coords);
return coords;
}
}

/**
* TODO symmetric getters and setters for fields to make this simpler to use
* in generic java tools
*
*/
public class ComponentPosition {

private int zIndex = -1;
private float top = -1;
private float right = -1;
private float bottom = -1;
private float left = -1;

private int topUnits;
private int rightUnits;
private int bottomUnits;
private int leftUnits;

/**
* Sets the position attributes using CSS syntax. Example usage:
*
* <code><pre>
* setCSSString("top:10px;left:20%;z-index:16;");
* </pre></code>
*
* @param css
*/
public void setCSSString(String css) {
String[] cssProperties = css.split(";");
for (int i = 0; i < cssProperties.length; i++) {
String[] keyValuePair = cssProperties[i].split(":");
String key = keyValuePair[0].trim();
if (key.equals("z-index")) {
zIndex = Integer.parseInt(keyValuePair[1]);
} else {
String value = keyValuePair[1].trim();
String unit = value.replaceAll("[0-9\\.]+", "");
if (!unit.equals("")) {
value = value.substring(0, value.indexOf(unit)).trim();
}
float v = Float.parseFloat(value);
int unitInt = parseCssUnit(unit);
if (key.equals("top")) {
top = v;
topUnits = unitInt;
} else if (key.equals("right")) {
right = v;
rightUnits = unitInt;
} else if (key.equals("bottom")) {
bottom = v;
bottomUnits = unitInt;
} else if (key.equals("left")) {
left = v;
leftUnits = unitInt;
}
}
}
requestRepaint();
}

private int parseCssUnit(String string) {
for (int i = 0; i < UNIT_SYMBOLS.length; i++) {
if (UNIT_SYMBOLS[i].equals(string)) {
return i;
}
}
return 0; // defaults to px (eg. top:0;)
}

public String getCSSString() {
String s = "";
if (top >= 0) {
s += "top:" + top + UNIT_SYMBOLS[topUnits] + ";";
}
if (right >= 0) {
s += "right:" + right + UNIT_SYMBOLS[rightUnits] + ";";
}
if (bottom >= 0) {
s += "bottom:" + bottom + UNIT_SYMBOLS[bottomUnits] + ";";
}
if (left >= 0) {
s += "left:" + left + UNIT_SYMBOLS[leftUnits] + ";";
}
if (zIndex >= 0) {
s += "z-index:" + zIndex + ";";
}
return s;
}

public void setTop(float topValue, int topUnits) {
validateLength(topValue, topUnits);
top = topValue;
this.topUnits = topUnits;
requestRepaint();
}

public void setRight(float rightValue, int rightUnits) {
validateLength(rightValue, rightUnits);
right = rightValue;
this.rightUnits = rightUnits;
requestRepaint();
}

public void setBottom(float bottomValue, int units) {
validateLength(bottomValue, units);
bottom = bottomValue;
bottomUnits = units;
requestRepaint();
}

public void setLeft(float leftValue, int units) {
validateLength(leftValue, units);
left = leftValue;
leftUnits = units;
requestRepaint();
}

public void setZIndex(int zIndex) {
this.zIndex = zIndex;
requestRepaint();
}

}

@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
for (Component component : components) {
target.startTag("cc");
target.addAttribute("css", getPosition(component).getCSSString());
component.paint(target);
target.endTag("cc");
}
}

private static void validateLength(float topValue, int topUnits2) {
// TODO throw on invalid value

}

}

Loading…
Cancel
Save