From 31d2e723890b1a96f7864afd690d165d6092fd58 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Fri, 5 Oct 2007 07:08:08 +0000 Subject: [PATCH] ContainerResizedListener, ISplitPanel refactoring, ExpandLayout and test svn changeset:2441/svn branch:trunk --- .../gwt/client/ApplicationConnection.java | 9 +- .../gwt/client/ContainerResizedListener.java | 16 + .../terminal/gwt/client/DefaultWidgetSet.java | 11 +- .../toolkit/terminal/gwt/client/Util.java | 21 ++ .../terminal/gwt/client/ui/IExpandLayout.java | 148 ++++++++++ .../gwt/client/ui/IOrderedLayout.java | 14 +- .../terminal/gwt/client/ui/ISplitPanel.java | 274 +++++++++++++----- .../toolkit/terminal/gwt/client/ui/ITree.java | 146 +++++----- .../toolkit/terminal/gwt/client/ui/IView.java | 17 +- .../gwt/public/default/common/common.css | 11 + .../default/expandlayout/expandlayout.css | 0 .../terminal/gwt/public/default/styles.css | 2 +- ...cationLayoutThatUsesWholeBrosersSpace.java | 58 ++++ ...ablesInitialColumnWidthLogicRendering.java | 2 +- src/com/itmill/toolkit/ui/ExpandLayout.java | 147 ++++++++++ src/com/itmill/toolkit/ui/Panel.java | 6 +- src/com/itmill/toolkit/ui/SplitPanel.java | 2 +- src/com/itmill/toolkit/ui/Table.java | 7 +- 18 files changed, 717 insertions(+), 174 deletions(-) create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/ContainerResizedListener.java create mode 100644 src/com/itmill/toolkit/terminal/gwt/client/ui/IExpandLayout.java create mode 100644 src/com/itmill/toolkit/terminal/gwt/public/default/expandlayout/expandlayout.css create mode 100644 src/com/itmill/toolkit/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java create mode 100644 src/com/itmill/toolkit/ui/ExpandLayout.java diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java index bd46973551..c5f63ac33a 100755 --- a/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ApplicationConnection.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Vector; -import com.google.gwt.core.client.EntryPoint; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; @@ -20,7 +19,6 @@ import com.google.gwt.user.client.ui.FocusListener; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.HasFocus; import com.google.gwt.user.client.ui.HasWidgets; -import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ui.ContextMenu; import com.itmill.toolkit.terminal.gwt.client.ui.IView; @@ -46,7 +44,7 @@ public class ApplicationConnection implements FocusListener { private ContextMenu contextMenu = null; - private IView view = new IView(); + private IView view; public ApplicationConnection(WidgetSet widgetSet) { this.widgetSet = widgetSet; @@ -59,9 +57,10 @@ public class ApplicationConnection implements FocusListener { } makeUidlRequest("repaintAll=1"); - + // TODO remove hardcoded id name - RootPanel.get("itmtk-ajax-window").add(view); + view = new IView("itmtk-ajax-window"); + } public static Console getConsole() { diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ContainerResizedListener.java b/src/com/itmill/toolkit/terminal/gwt/client/ContainerResizedListener.java new file mode 100644 index 0000000000..7248b1d921 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/client/ContainerResizedListener.java @@ -0,0 +1,16 @@ +package com.itmill.toolkit.terminal.gwt.client; + +/** + * ContainerResizedListener interface is useful for Widgets that support + * relative sizes and who need some additional sizing logic. + */ +public interface ContainerResizedListener { + /** + * This function is run when container box has been resized. Object + * implementing ContainerResizedListener is responsible to call the same + * function on its ancestors that implement NeedsLayout in case their + * container has resized. runAnchestorsLayout(HasWidgets parent) function + * from Util class may be a good helper for this. + */ + public void iLayout(); +} diff --git a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java index 2f67f6fbf4..baaef447d1 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/DefaultWidgetSet.java @@ -8,6 +8,7 @@ import com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox; import com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout; import com.itmill.toolkit.terminal.gwt.client.ui.IDateFieldCalendar; import com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded; +import com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout; import com.itmill.toolkit.terminal.gwt.client.ui.IFilterSelect; import com.itmill.toolkit.terminal.gwt.client.ui.IForm; import com.itmill.toolkit.terminal.gwt.client.ui.IFormLayout; @@ -35,7 +36,6 @@ import com.itmill.toolkit.terminal.gwt.client.ui.ITree; import com.itmill.toolkit.terminal.gwt.client.ui.ITwinColSelect; import com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent; import com.itmill.toolkit.terminal.gwt.client.ui.IUpload; -import com.itmill.toolkit.terminal.gwt.client.ui.IView; import com.itmill.toolkit.terminal.gwt.client.ui.IWindow; public class DefaultWidgetSet implements WidgetSet { @@ -58,10 +58,6 @@ public class DefaultWidgetSet implements WidgetSet { } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IButton" .equals(className)) { return new IButton(); - } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IView" - .equals(className)) { - // TODO remove IView? - return new IView(); } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IWindow" .equals(className)) { return new IWindow(); @@ -155,6 +151,9 @@ public class DefaultWidgetSet implements WidgetSet { } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator" .equals(className)) { return new IProgressIndicator(); + } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout" + .equals(className)) { + return new IExpandLayout(); } return new IUnknownComponent(); @@ -248,6 +247,8 @@ public class DefaultWidgetSet implements WidgetSet { return "com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelVertical"; } else if ("progressindicator".equals(tag)) { return "com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator"; + } else if ("expandlayout".equals(tag)) { + return "com.itmill.toolkit.terminal.gwt.client.ui.IExpandLayout"; } return "com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent"; diff --git a/src/com/itmill/toolkit/terminal/gwt/client/Util.java b/src/com/itmill/toolkit/terminal/gwt/client/Util.java index 0a93dde18f..9af2794ff0 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/Util.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/Util.java @@ -1,6 +1,10 @@ package com.itmill.toolkit.terminal.gwt.client; +import java.util.Iterator; + import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.HasWidgets; +import com.google.gwt.user.client.ui.Widget; public class Util { @@ -40,4 +44,21 @@ public class Util { el.oncontextmenu = null; }-*/; + /** + * Traverses recursively ancestors until ContainerResizedListener child widget is found. + * They will delegate it futher if needed. + * @param container + */ + public static void runAnchestorsLayout(HasWidgets container) { + Iterator childWidgets = container.iterator(); + while (childWidgets.hasNext()) { + Widget child = (Widget) childWidgets.next(); + if (child instanceof ContainerResizedListener) { + ((ContainerResizedListener) child).iLayout(); + } else if (child instanceof HasWidgets) { + HasWidgets childContainer = (HasWidgets) child; + runAnchestorsLayout(childContainer); + } + } + } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IExpandLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IExpandLayout.java new file mode 100644 index 0000000000..7fe485aa96 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IExpandLayout.java @@ -0,0 +1,148 @@ +package com.itmill.toolkit.terminal.gwt.client.ui; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; +import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener; +import com.itmill.toolkit.terminal.gwt.client.Paintable; +import com.itmill.toolkit.terminal.gwt.client.UIDL; +import com.itmill.toolkit.terminal.gwt.client.Util; + +/** + * TODO make this work horizontally + * + * @author IT Mill Ltd + */ +public class IExpandLayout extends IOrderedLayout implements ContainerResizedListener { + + private Widget expandedWidget; + private UIDL expandedWidgetUidl; + + public IExpandLayout() { + super(IOrderedLayout.ORIENTATION_VERTICAL); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + this.client = client; + + // Ensure correct implementation + if (client.updateComponent(this, uidl, false)) + return; + + String h = uidl.getStringAttribute("height"); + setHeight(h); + String w = uidl.getStringAttribute("width"); + setWidth(w); + + ArrayList uidlWidgets = new ArrayList(); + for (Iterator it = uidl.getChildIterator(); it.hasNext();) { + UIDL cellUidl = (UIDL) it.next(); + Widget child = client.getWidget(cellUidl.getChildUIDL(0)); + uidlWidgets.add(child); + if (cellUidl.hasAttribute("expanded")) { + expandedWidget = child; + expandedWidgetUidl = cellUidl.getChildUIDL(0); + } + } + + ArrayList oldWidgets = getPaintables(); + + Iterator oldIt = oldWidgets.iterator(); + Iterator newIt = uidlWidgets.iterator(); + Iterator newUidl = uidl.getChildIterator(); + + Widget oldChild = null; + while (newIt.hasNext()) { + Widget child = (Widget) newIt.next(); + UIDL childUidl = ((UIDL) newUidl.next()).getChildUIDL(0); + if (oldChild == null && oldIt.hasNext()) { + // search for next old Paintable which still exists in layout + // and delete others + while (oldIt.hasNext()) { + oldChild = (Widget) oldIt.next(); + // now oldChild is an instance of Paintable + if (uidlWidgets.contains(oldChild)) + break; + else { + removePaintable((Paintable) oldChild); + oldChild = null; + } + } + } + if (oldChild == null) { + // we are adding components to layout + add(child); + } else if (child == oldChild) { + // child already attached and updated + oldChild = null; + } else if (hasChildComponent(child)) { + // current child has been moved, re-insert before current + // oldChild + // TODO this might be optimized by moving only container element + // to correct position + removeCaption(child); + int index = getWidgetIndex(oldChild); + if (componentToCaption.containsKey(oldChild)) + index--; + remove(child); + this.insert(child, index); + } else { + // insert new child before old one + int index = getWidgetIndex(oldChild); + insert(child, index); + } + if (child != expandedWidget) + ((Paintable) child).updateFromUIDL(childUidl, client); + } + // remove possibly remaining old Paintable object which were not updated + while (oldIt.hasNext()) { + oldChild = (Widget) oldIt.next(); + Paintable p = (Paintable) oldChild; + if (!uidlWidgets.contains(p)) + removePaintable(p); + } + + iLayout(); + + /* + * Expanded widget is updated after layout function so it has its + * container fixed at the moment of updateFromUIDL. + */ + ((Paintable) expandedWidget).updateFromUIDL(expandedWidgetUidl, client); + + } + + public void iLayout() { +// ApplicationConnection.getConsole().log("EL layouting..."); + Element expandedElement = DOM.getParent(expandedWidget.getElement()); + String origDisplay = DOM.getStyleAttribute(expandedElement, "display"); + DOM.setStyleAttribute(expandedElement, "display", "none"); + + // add temp element to make some measurements + Element meter = createWidgetWrappper(); + DOM.setStyleAttribute(meter, "overflow", "hidden"); + DOM.setStyleAttribute(meter, "height", "1px"); + DOM.appendChild(childContainer, meter); + int usedSpace = DOM.getElementPropertyInt(meter, "offsetTop") + - DOM.getElementPropertyInt(DOM.getFirstChild(childContainer), + "offsetTop"); +// ApplicationConnection.getConsole().log("EL h" + getOffsetHeight()); +// ApplicationConnection.getConsole().log("EL h" + getOffsetHeight()); + int freeSpace = getOffsetHeight() - usedSpace; + + DOM.setStyleAttribute(expandedElement, + "height", freeSpace + "px"); + + DOM.setStyleAttribute(expandedElement, "display", origDisplay); + + DOM.removeChild(childContainer, meter); + + // TODO save previous size and only propagate if really changed + Util.runAnchestorsLayout(this); + } + +} diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java index f19e0829cb..d7048cd375 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java @@ -29,15 +29,15 @@ public abstract class IOrderedLayout extends ComplexPanel implements Container { int orientationMode = ORIENTATION_VERTICAL; - private HashMap componentToCaption = new HashMap(); + protected HashMap componentToCaption = new HashMap(); - private ApplicationConnection client; + protected ApplicationConnection client; /** * Contains reference to Element where Paintables are wrapped. For horizontal * layout this is TR and for vertical DIV. */ - private Element childContainer; + protected Element childContainer; public IOrderedLayout(int orientation) { orientationMode = orientation; @@ -45,7 +45,7 @@ public abstract class IOrderedLayout extends ComplexPanel implements Container { setStyleName(CLASSNAME); } - private void constructDOM() { + protected void constructDOM() { switch (orientationMode) { case ORIENTATION_HORIZONTAL: Element table = DOM.createTable(); @@ -139,7 +139,7 @@ public abstract class IOrderedLayout extends ComplexPanel implements Container { * * @return list of Paintable objects */ - private ArrayList getPaintables() { + protected ArrayList getPaintables() { ArrayList al = new ArrayList(); Iterator it = iterator(); while (it.hasNext()) { @@ -184,7 +184,7 @@ public abstract class IOrderedLayout extends ComplexPanel implements Container { } } - private void insert(Widget w, int beforeIndex) { + protected void insert(Widget w, int beforeIndex) { if (w instanceof Caption) { Caption c = (Caption) w; // captions go into same container element as their @@ -203,7 +203,7 @@ public abstract class IOrderedLayout extends ComplexPanel implements Container { /** * creates an Element which will contain child widget */ - private Element createWidgetWrappper() { + protected Element createWidgetWrappper() { switch (orientationMode) { case ORIENTATION_HORIZONTAL: return DOM.createTD(); diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ISplitPanel.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ISplitPanel.java index 97a73a2f19..ef081144e6 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ISplitPanel.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ISplitPanel.java @@ -1,132 +1,264 @@ package com.itmill.toolkit.terminal.gwt.client.ui; -import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.HorizontalSplitPanel; -import com.google.gwt.user.client.ui.HorizontalSplitPanelImages; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.VerticalSplitPanel; -import com.google.gwt.user.client.ui.VerticalSplitPanelImages; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; +import com.itmill.toolkit.terminal.gwt.client.ContainerResizedListener; import com.itmill.toolkit.terminal.gwt.client.Paintable; import com.itmill.toolkit.terminal.gwt.client.UIDL; +import com.itmill.toolkit.terminal.gwt.client.Util; -public class ISplitPanel extends SimplePanel implements Paintable { +public class ISplitPanel extends ComplexPanel implements Paintable, ContainerResizedListener { public static final String CLASSNAME = "i-splitpanel"; + public static final int ORIENTATION_HORIZONTAL = 0; public static final int ORIENTATION_VERTICAL = 1; - + + private static final int SPLITTER_SIZE = 8; + private int orientation; - private HorizontalSplitPanel sph; - private VerticalSplitPanel spv; private Widget firstChild; private Widget secondChild; - + + private Element wrapper = DOM.createDiv(); + private Element firstContainer = DOM.createDiv(); + private Element secondContainer = DOM.createDiv(); + private Element splitter = DOM.createDiv(); + + private boolean resizing; + + private int origX; + + private int origY; + + private int origMouseX; + + private int origMouseY; + public ISplitPanel() { this(ORIENTATION_HORIZONTAL); } - + public ISplitPanel(int orientation) { - super(); + setElement(DOM.createDiv()); + setStyleName(CLASSNAME); + constructDom(); setOrientation(orientation); + setSplitPosition("50%"); + DOM.sinkEvents(splitter, Event.MOUSEEVENTS); + } + + protected void constructDom() { + DOM.appendChild(getElement(), wrapper); + DOM.setStyleAttribute(wrapper, "position", "relative"); + DOM.setStyleAttribute(wrapper, "width", "100%"); + DOM.setStyleAttribute(wrapper, "height", "100%"); + + DOM.appendChild(wrapper, splitter); + DOM.appendChild(wrapper, secondContainer); + DOM.appendChild(wrapper, firstContainer); + + DOM.setStyleAttribute(splitter, "position", "absolute"); + DOM.setStyleAttribute(secondContainer, "position", "absolute"); + DOM.setElementProperty(splitter, "className", "splitter"); + DOM.setStyleAttribute(splitter, "background", "cyan"); + + DOM.setStyleAttribute(firstContainer, "overflow", "hidden"); + DOM.setStyleAttribute(secondContainer, "overflow", "hidden"); + } - + private void setOrientation(int orientation) { this.orientation = orientation; - if(orientation == ORIENTATION_HORIZONTAL) { - this.sph = new HorizontalSplitPanel((HorizontalSplitPanelImages) GWT.create(com.itmill.toolkit.terminal.gwt.client.ui.HorizontalSplitPanelImages.class)); - this.sph.setStyleName(CLASSNAME+"-horizontal"); - // Ugly work-around to allow more advanced styling (GWT's heavy use of TABLE-elements is restricting) - Element handle = DOM.getChild(DOM.getChild(this.sph.getElement(), 0), 1); - DOM.setElementAttribute(handle, "className", CLASSNAME+"-handle"); - this.setWidget(sph); - if(spv != null) { - // TODO cleanup contained widgets - this.spv = null; - } + if (orientation == ORIENTATION_HORIZONTAL) { + DOM.setStyleAttribute(splitter, "height", "100%"); + DOM.setStyleAttribute(splitter, "width", SPLITTER_SIZE + "px"); + DOM.setStyleAttribute(firstContainer, "height", "100%"); + DOM.setStyleAttribute(secondContainer, "height", "100%"); } else { - this.spv = new VerticalSplitPanel((VerticalSplitPanelImages) GWT.create(com.itmill.toolkit.terminal.gwt.client.ui.VerticalSplitPanelImages.class)); - this.spv.setStyleName(CLASSNAME+"-vertical"); - // Ugly work-around to allow more advanced styling (GWT's heavy use of TABLE-elements is restricting) - Element handle = DOM.getChild(DOM.getChild(this.spv.getElement(), 0), 1); - DOM.setElementAttribute(handle, "className", CLASSNAME+"-handle"); - this.setWidget(spv); - if(sph != null) { - // TODO cleanup contained widgets - this.sph = null; - } + DOM.setStyleAttribute(splitter, "width", "100%"); + DOM.setStyleAttribute(splitter, "height", SPLITTER_SIZE + "px"); + DOM.setStyleAttribute(firstContainer, "width", "100%"); + DOM.setStyleAttribute(secondContainer, "width", "100%"); } } public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { client.updateComponent(this, uidl, true); - - setSplitPosition(uidl.getStringAttribute("position")); - + setWidth(uidl.getStringAttribute("width")); setHeight(uidl.getStringAttribute("height")); - - - Paintable newFirstChild = (Paintable) client.getWidget(uidl.getChildUIDL(0)); - Paintable newSecondChild = (Paintable) client.getWidget(uidl.getChildUIDL(1)); - if(firstChild != newFirstChild) { - if(firstChild != null) + + setSplitPosition(uidl.getStringAttribute("position")); + + Paintable newFirstChild = (Paintable) client.getWidget(uidl + .getChildUIDL(0)); + Paintable newSecondChild = (Paintable) client.getWidget(uidl + .getChildUIDL(1)); + if (firstChild != newFirstChild) { + if (firstChild != null) client.unregisterPaintable((Paintable) firstChild); setFirstWidget((Widget) newFirstChild); } - if(secondChild != newSecondChild) { - if(secondChild != null) + if (secondChild != newSecondChild) { + if (secondChild != null) client.unregisterPaintable((Paintable) secondChild); setSecondWidget((Widget) newSecondChild); } newFirstChild.updateFromUIDL(uidl.getChildUIDL(0), client); newSecondChild.updateFromUIDL(uidl.getChildUIDL(1), client); } - + private void setSplitPosition(String pos) { - if(orientation == ORIENTATION_HORIZONTAL) { - this.sph.setSplitPosition(pos); + if (orientation == ORIENTATION_HORIZONTAL) { + DOM.setStyleAttribute(splitter, "left", pos); } else { - this.spv.setSplitPosition(pos); + DOM.setStyleAttribute(splitter, "top", pos); } + iLayout(); + } + + /* + * Calculates absolutely positioned container places/sizes (non-Javadoc) + * + * @see com.itmill.toolkit.terminal.gwt.client.NeedsLayout#layout() + */ + public void iLayout() { + int wholeSize; + int pixelPosition; + switch (orientation) { + case ORIENTATION_HORIZONTAL: + wholeSize = DOM.getElementPropertyInt(wrapper, "clientWidth"); + pixelPosition = DOM.getElementPropertyInt(splitter, "offsetLeft"); + + DOM + .setStyleAttribute(firstContainer, "width", pixelPosition + + "px"); + DOM.setStyleAttribute(secondContainer, "width", (wholeSize + - pixelPosition - SPLITTER_SIZE) + + "px"); + DOM.setStyleAttribute(secondContainer, "left", + (pixelPosition + SPLITTER_SIZE) + "px"); + + break; + case ORIENTATION_VERTICAL: + wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight"); + pixelPosition = DOM.getElementPropertyInt(splitter, "offsetTop"); + + DOM.setStyleAttribute(firstContainer, "height", pixelPosition + + "px"); + DOM.setStyleAttribute(secondContainer, "height", (wholeSize + - pixelPosition - SPLITTER_SIZE) + + "px"); + DOM.setStyleAttribute(secondContainer, "top", + (pixelPosition + SPLITTER_SIZE) + "px"); + + default: + + break; + } + + Util.runAnchestorsLayout(this); } private void setFirstWidget(Widget w) { - firstChild = w; - if(orientation == ORIENTATION_HORIZONTAL) { - this.sph.setLeftWidget(w); - } else { - this.spv.setTopWidget(w); + if (firstChild != null) { + firstChild.removeFromParent(); } + super.add(w, firstContainer); + firstChild = w; } - + private void setSecondWidget(Widget w) { - secondChild = w; - if(orientation == ORIENTATION_HORIZONTAL) { - this.sph.setRightWidget(w); - } else { - this.spv.setBottomWidget(w); + if (secondChild != null) { + secondChild.removeFromParent(); } + super.add(w, secondContainer); + secondChild = w; } public void setHeight(String height) { super.setHeight(height); - if(orientation == ORIENTATION_HORIZONTAL) { - sph.setHeight(height); - } else { - spv.setHeight(height); - } } public void setWidth(String width) { super.setWidth(width); - if(orientation == ORIENTATION_HORIZONTAL) { - sph.setWidth(width); - } else { - spv.setWidth(width); + } + + public void onBrowserEvent(Event event) { + switch (DOM.eventGetType(event)) { + case Event.ONMOUSEMOVE: + if (resizing) { + onMouseMove(event); + } + break; + case Event.ONMOUSEDOWN: + onMouseDown(event); + break; + case Event.ONMOUSEUP: + onMouseUp(event); + break; } } - + + public void onMouseDown(Event event) { + resizing = true; + DOM.setCapture(getElement()); + origX = DOM.getAbsoluteLeft(splitter); + origY = DOM.getAbsoluteTop(splitter); + origMouseX = DOM.eventGetClientX(event); + origMouseY = DOM.eventGetClientY(event); + DOM.eventCancelBubble(event, true); + DOM.eventPreventDefault(event); + } + + public void onMouseEnter(Widget sender) { + } + + public void onMouseLeave(Widget sender) { + } + + public void onMouseMove(Event event) { + switch (orientation) { + case ORIENTATION_HORIZONTAL: + int x = DOM.eventGetClientX(event); + onHorizontalMouseMove(x); + break; + case ORIENTATION_VERTICAL: + default: + int y = DOM.eventGetClientY(event); + onVerticalMouseMove(y); + break; + } + iLayout(); + } + + private void onHorizontalMouseMove(int x) { + int newX = origX + x - origMouseX; + if (newX < 0) + newX = 0; + if (newX + SPLITTER_SIZE > getOffsetWidth()) + newX = getOffsetWidth() - SPLITTER_SIZE; + DOM.setStyleAttribute(splitter, "left", newX + "px"); + } + + private void onVerticalMouseMove(int y) { + int newY = origY + y - origMouseY; + if (newY < 0) + newY = 0; + + if (newY + SPLITTER_SIZE > getOffsetHeight()) + newY = getOffsetHeight() - SPLITTER_SIZE; + DOM.setStyleAttribute(splitter, "top", newY + "px"); + } + + public void onMouseUp(Event event) { + onMouseMove(event); + resizing = false; + DOM.releaseCapture(getElement()); + } + } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java index e8411096d7..5f7da590f3 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/ITree.java @@ -18,14 +18,14 @@ import com.itmill.toolkit.terminal.gwt.client.UIDL; import com.itmill.toolkit.terminal.gwt.client.Util; /** - * TODO dump GWT's Tree implementation and use Toolkit 4 style - * TODO update node close/opens to server (even if no content fetch is needed) + * TODO dump GWT's Tree implementation and use Toolkit 4 style TODO update node + * close/opens to server (even if no content fetch is needed) * * DOM structure - * + * */ public class ITree extends Tree implements Paintable { - + public static final String CLASSNAME = "i-tree"; Set selectedIds = new HashSet(); @@ -33,69 +33,65 @@ public class ITree extends Tree implements Paintable { String paintableId; private boolean selectable; private boolean multiselect; - + private HashMap keyToNode = new HashMap(); - + /** - * This map contains captions and icon urls for - * actions like: - * * "33_c" -> "Edit" - * * "33_i" -> "http://dom.com/edit.png" + * This map contains captions and icon urls for actions like: * "33_c" -> + * "Edit" * "33_i" -> "http://dom.com/edit.png" */ private HashMap actionMap = new HashMap(); private boolean immediate; - public ITree() { super(); setStyleName(CLASSNAME); } - + private void updateActionMap(UIDL c) { Iterator it = c.getChildIterator(); - while(it.hasNext()) { + while (it.hasNext()) { UIDL action = (UIDL) it.next(); String key = action.getStringAttribute("key"); String caption = action.getStringAttribute("caption"); actionMap.put(key + "_c", caption); - if(action.hasAttribute("icon")) { + if (action.hasAttribute("icon")) { // TODO need some uri handling ?? actionMap.put(key + "_i", action.getStringAttribute("icon")); } } - + } - + public String getActionCaption(String actionKey) { return (String) actionMap.get(actionKey + "_c"); } - + public String getActionIcon(String actionKey) { return (String) actionMap.get(actionKey + "_i"); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { // Ensure correct implementation and let container manage caption if (client.updateComponent(this, uidl, true)) return; - + this.client = client; - - if(uidl.hasAttribute("partialUpdate")) { + + if (uidl.hasAttribute("partialUpdate")) { handleUpdate(uidl); return; } - + this.paintableId = uidl.getId(); - + this.immediate = uidl.hasAttribute("immediate"); - + clear(); for (Iterator i = uidl.getChildIterator(); i.hasNext();) { - UIDL childUidl = (UIDL)i.next(); - if("actions".equals(childUidl.getTag())){ + UIDL childUidl = (UIDL) i.next(); + if ("actions".equals(childUidl.getTag())) { updateActionMap(childUidl); continue; } @@ -106,29 +102,31 @@ public class ITree extends Tree implements Paintable { String selectMode = uidl.getStringAttribute("selectmode"); selectable = selectMode != null; multiselect = "multi".equals(selectMode); - + addTreeListener(new TreeListener() { - + public void onTreeItemStateChanged(TreeItem item) { if (item instanceof TreeNode) { TreeNode tn = (TreeNode) item; - if(item.getState()) { - if(!tn.isChildrenLoaded()) { + if (item.getState()) { + if (!tn.isChildrenLoaded()) { String key = tn.key; - ITree.this.client.updateVariable(paintableId, "expand", new String[] {key}, true); + ITree.this.client.updateVariable(paintableId, + "expand", new String[] { key }, true); } } else { // TODO collapse } } } - + public void onTreeItemSelected(TreeItem item) { TreeNode n = ((TreeNode) item); - if (!selectable) return; + if (!selectable) + return; String key = n.key; if (key != null) { - if(selectedIds.contains(key) && multiselect) { + if (selectedIds.contains(key) && multiselect) { selectedIds.remove(key); n.setISelected(false); } else { @@ -138,46 +136,48 @@ public class ITree extends Tree implements Paintable { selectedIds.add(key); n.setISelected(true); } - ITree.this.client.updateVariable(ITree.this.paintableId, "selected", selectedIds.toArray(), immediate); + ITree.this.client.updateVariable(ITree.this.paintableId, + "selected", selectedIds.toArray(), immediate); } } - + }); - + selectedIds = uidl.getStringArrayVariableAsSet("selected"); - + } - + private void handleUpdate(UIDL uidl) { - TreeNode rootNode = (TreeNode) keyToNode.get(uidl.getStringAttribute("rootKey")); - if(rootNode != null) { + TreeNode rootNode = (TreeNode) keyToNode.get(uidl + .getStringAttribute("rootKey")); + if (rootNode != null) { rootNode.renderChildNodes(uidl.getChildIterator()); } - + } private class TreeNode extends TreeItem implements ActionOwner { - + String key; - + boolean isLeaf = false; - + private String[] actionKeys = null; private boolean childrenLoaded; - + public TreeNode() { super(); attachContextMenuEvent(getElement()); } - + public void remove() { Util.removeContextMenuEvent(getElement()); super.remove(); } public void setSelected(boolean selected) { - if(!selected && !ITree.this.multiselect) { + if (!selected && !ITree.this.multiselect) { this.setISelected(false); } super.setSelected(selected); @@ -186,15 +186,15 @@ public class ITree extends Tree implements Paintable { public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { this.setText(uidl.getStringAttribute("caption")); key = uidl.getStringAttribute("key"); - + keyToNode.put(key, this); - - if(uidl.hasAttribute("al")) + + if (uidl.hasAttribute("al")) actionKeys = uidl.getStringArrayAttribute("al"); - - if(uidl.getTag().equals("node")) { + + if (uidl.getTag().equals("node")) { isLeaf = false; - if(uidl.getChidlCount() == 0) { + if (uidl.getChidlCount() == 0) { TreeNode childTree = new TreeNode(); childTree.setText("Loading..."); childrenLoaded = false; @@ -205,20 +205,20 @@ public class ITree extends Tree implements Paintable { } else { isLeaf = true; } - - if(uidl.getBooleanAttribute("expanded") && !getState()) { + + if (uidl.getBooleanAttribute("expanded") && !getState()) { setState(true); } - + setSelected(uidl.getBooleanAttribute("selected")); - + } - + private void renderChildNodes(Iterator i) { removeItems(); while (i.hasNext()) { - UIDL childUidl = (UIDL)i.next(); - if("actions".equals(childUidl.getTag())) { + UIDL childUidl = (UIDL) i.next(); + if ("actions".equals(childUidl.getTag())) { updateActionMap(childUidl); continue; } @@ -228,18 +228,19 @@ public class ITree extends Tree implements Paintable { } childrenLoaded = true; } - + public boolean isChildrenLoaded() { return childrenLoaded; } public Action[] getActions() { - if(actionKeys == null) + if (actionKeys == null) return new Action[] {}; Action[] actions = new Action[actionKeys.length]; for (int i = 0; i < actions.length; i++) { String actionKey = actionKeys[i]; - TreeAction a = new TreeAction(this, String.valueOf(key), actionKey); + TreeAction a = new TreeAction(this, String.valueOf(key), + actionKey); a.setCaption(getActionCaption(actionKey)); a.setIconUrl(getActionIcon(actionKey)); actions[i] = a; @@ -254,19 +255,19 @@ public class ITree extends Tree implements Paintable { public String getPaintableId() { return paintableId; } - + /** - * Adds/removes IT Mill Toolkit spesific style name. - * (GWT treenode does not support multiselects) + * Adds/removes IT Mill Toolkit spesific style name. (GWT treenode does + * not support multiselects) * * @param selected */ public void setISelected(boolean selected) { setStyleName(getElement(), "i-tree-node-selected", selected); } - + public void showContextMenu(Event event) { - if(actionKeys != null) { + if (actionKeys != null) { int left = DOM.eventGetClientX(event); int top = DOM.eventGetClientY(event); top += Window.getScrollTop(); @@ -275,8 +276,9 @@ public class ITree extends Tree implements Paintable { } DOM.eventCancelBubble(event, true); } - - private native void attachContextMenuEvent(Element el) /*-{ + + private native void attachContextMenuEvent(Element el) + /*-{ var node = this; el.oncontextmenu = function(e) { if(!e) @@ -285,6 +287,6 @@ public class ITree extends Tree implements Paintable { return false; }; }-*/; - + } } diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java index d937447005..d06f40e6f8 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IView.java @@ -6,6 +6,7 @@ import java.util.Iterator; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.WindowResizeListener; import com.google.gwt.user.client.ui.KeyboardListenerCollection; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; @@ -13,12 +14,15 @@ import com.google.gwt.user.client.ui.Widget; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; import com.itmill.toolkit.terminal.gwt.client.Paintable; import com.itmill.toolkit.terminal.gwt.client.UIDL; +import com.itmill.toolkit.terminal.gwt.client.Util; /** * */ -public class IView extends SimplePanel implements Paintable { +public class IView extends SimplePanel implements Paintable, WindowResizeListener { + private static final String CLASSNAME = "i-view"; + private String theme; private Paintable layout; @@ -29,9 +33,14 @@ public class IView extends SimplePanel implements Paintable { private ShortcutActionHandler actionHandler; - public IView() { + public IView(String elementId) { super(); + setStyleName(CLASSNAME); DOM.sinkEvents(getElement(), Event.ONKEYDOWN); + + RootPanel.get(elementId).add(this); + + Window.addWindowResizeListener(this); } public String getTheme() { @@ -118,5 +127,9 @@ public class IView extends SimplePanel implements Paintable { } } + public void onWindowResized(int width, int height) { + Util.runAnchestorsLayout(this); + } + } diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/common/common.css b/src/com/itmill/toolkit/terminal/gwt/public/default/common/common.css index 5140d1623d..83fb91f904 100644 --- a/src/com/itmill/toolkit/terminal/gwt/public/default/common/common.css +++ b/src/com/itmill/toolkit/terminal/gwt/public/default/common/common.css @@ -1,9 +1,20 @@ +html, body { + margin:0; + padding:0; + height:100%; +} + #itmtk-ajax-window { background: #e9eced; font-family: "Trebuchet MS", geneva, helvetica, arial, tahoma, verdana, sans-serif; color: #464f52; font-size: 12px; line-height: 18px; + height:100%; +} + +.i-view { + height:100%; } input, select, textarea, button { diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/expandlayout/expandlayout.css b/src/com/itmill/toolkit/terminal/gwt/public/default/expandlayout/expandlayout.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/com/itmill/toolkit/terminal/gwt/public/default/styles.css b/src/com/itmill/toolkit/terminal/gwt/public/default/styles.css index 6b686274c0..e5e037f988 100644 --- a/src/com/itmill/toolkit/terminal/gwt/public/default/styles.css +++ b/src/com/itmill/toolkit/terminal/gwt/public/default/styles.css @@ -13,4 +13,4 @@ @import "splitpanel/splitpanel.css"; @import "select/filterselect.css"; @import "progressindicator/progressindicator.css"; - +@import "expandlayout/expandlayout.css"; diff --git a/src/com/itmill/toolkit/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java b/src/com/itmill/toolkit/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java new file mode 100644 index 0000000000..fd56c21543 --- /dev/null +++ b/src/com/itmill/toolkit/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java @@ -0,0 +1,58 @@ +package com.itmill.toolkit.tests; + +import com.itmill.toolkit.Application; +import com.itmill.toolkit.ui.*; + +public class TestForApplicationLayoutThatUsesWholeBrosersSpace extends + Application { + + Window main = new Window("Windowing test"); + + ExpandLayout rootLayout; + + SplitPanel firstLevelSplit; + + public void init() { + setMainWindow(main); + + rootLayout = new ExpandLayout(); + main.setLayout(rootLayout); + + rootLayout.addComponent(new Label("header")); + + firstLevelSplit = new SplitPanel(); + + SplitPanel secondSplitPanel = new SplitPanel( + SplitPanel.ORIENTATION_HORIZONTAL); + secondSplitPanel.setFirstComponent(new Label("left")); + + ExpandLayout topRight = new ExpandLayout(); + topRight.addComponent(new Label("topright header")); + + Table t = TestForTablesInitialColumnWidthLogicRendering.getTestTable(4, 100); + t.setWidth(100); + t.setWidthUnits(Table.UNITS_PERCENTAGE); + t.setHeight(100); + t.setHeightUnits(Table.UNITS_PIXELS); + topRight.addComponent(t); + topRight.expand(t); + + topRight.addComponent(new Label("topright footer")); + + secondSplitPanel.setSecondComponent(topRight); + + + ExpandLayout el = new ExpandLayout(); + el.addComponent(new Label("Bšš")); + + firstLevelSplit.setFirstComponent(secondSplitPanel); + firstLevelSplit.setSecondComponent(el); + + rootLayout.addComponent(firstLevelSplit); + rootLayout.expand(firstLevelSplit); + + rootLayout.addComponent(new Label("footer")); + + } + +} diff --git a/src/com/itmill/toolkit/tests/TestForTablesInitialColumnWidthLogicRendering.java b/src/com/itmill/toolkit/tests/TestForTablesInitialColumnWidthLogicRendering.java index 33727289f5..1fafe4c26e 100644 --- a/src/com/itmill/toolkit/tests/TestForTablesInitialColumnWidthLogicRendering.java +++ b/src/com/itmill/toolkit/tests/TestForTablesInitialColumnWidthLogicRendering.java @@ -83,7 +83,7 @@ public class TestForTablesInitialColumnWidthLogicRendering extends CustomCompone } - public Table getTestTable(int cols, int rows) { + public static Table getTestTable(int cols, int rows) { Table t = new Table(); t.setColumnCollapsingAllowed(true); for(int i = 0; i < cols; i++) { diff --git a/src/com/itmill/toolkit/ui/ExpandLayout.java b/src/com/itmill/toolkit/ui/ExpandLayout.java new file mode 100644 index 0000000000..a03d18f210 --- /dev/null +++ b/src/com/itmill/toolkit/ui/ExpandLayout.java @@ -0,0 +1,147 @@ +package com.itmill.toolkit.ui; + +import java.util.Iterator; + +import com.itmill.toolkit.terminal.PaintException; +import com.itmill.toolkit.terminal.PaintTarget; +import com.itmill.toolkit.terminal.Sizeable; + +/** + * TODO finish documentation + * + * our layouts (except custom layout of course) don't currently work at all with + * relative widths. This layout tries to cope with this issue. + * + * basically this is ordered layout which has Sizeable interface 100 % height & + * width by default + * + * all contained components may also have Sizeable interfaces sizes + * + * can be used to build flexible layout where some component gets all the space + * other components don't use. Or just provide expanded container. + * + */ +public class ExpandLayout extends OrderedLayout implements Sizeable { + + private int height = 100; + + private int width = 100; + + private int widthUnit = UNITS_PERCENTAGE; + + private int heightUnit = UNITS_PERCENTAGE; + + private Component expanded; + + public ExpandLayout() { + + } + + /** + * @param c + * Component which container will be maximized + */ + public void expand(Component c) { + this.expanded = c; + requestRepaint(); + } + + public String getTag() { + return "expandlayout"; + } + + public void paintContent(PaintTarget target) throws PaintException { + // Size + if (getHeight() >= 0) + target.addAttribute("height", "" + getHeight() + + Sizeable.UNIT_SYMBOLS[getHeightUnits()]); + if (getWidth() >= 0) + target.addAttribute("width", "" + getWidth() + + Sizeable.UNIT_SYMBOLS[getWidthUnits()]); + + // Adds the attributes: orientation + // note that the default values (b/vertival) are omitted + if (getOrientation() == ORIENTATION_HORIZONTAL) + target.addAttribute("orientation", "horizontal"); + + // Adds all items in all the locations + for (Iterator i = getComponentIterator(); i.hasNext();) { + Component c = (Component) i.next(); + if (c != null) { + target.startTag("cc"); + if (c == expanded) + target.addAttribute("expanded", true); + c.paint(target); + target.endTag("cc"); + } + } + } + + public void addComponent(Component c, int index) { + if (expanded == null) { + expanded = c; + } + super.addComponent(c, index); + } + + public void addComponent(Component c) { + if (expanded == null) { + expanded = c; + } + super.addComponent(c); + } + + public void addComponentAsFirst(Component c) { + if (expanded == null) { + expanded = c; + } + super.addComponentAsFirst(c); + } + + public void removeComponent(Component c) { + super.removeComponent(c); + if (c == expanded && this.getComponentIterator().hasNext()) + expanded = (Component) this.getComponentIterator().next(); + else + expanded = null; + } + + public void replaceComponent(Component oldComponent, Component newComponent) { + super.replaceComponent(oldComponent, newComponent); + if(oldComponent == expanded) + expanded = newComponent; + } + + public int getHeight() { + return height; + } + + public int getHeightUnits() { + return heightUnit; + } + + public int getWidth() { + return width; + } + + public int getWidthUnits() { + return widthUnit; + } + + public void setHeight(int height) { + this.height = height; + + } + + public void setHeightUnits(int units) { + this.heightUnit = units; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setWidthUnits(int units) { + this.widthUnit = units; + } +} diff --git a/src/com/itmill/toolkit/ui/Panel.java b/src/com/itmill/toolkit/ui/Panel.java index 19022851c0..80444cc94b 100644 --- a/src/com/itmill/toolkit/ui/Panel.java +++ b/src/com/itmill/toolkit/ui/Panel.java @@ -401,8 +401,7 @@ public class Panel extends AbstractComponentContainer implements Sizeable, } /** - * Sets the height units. Panel supports only Sizeable.UNITS_PIXELS and this - * is ignored. + * Sets the height units. * * @see com.itmill.toolkit.terminal.Sizeable#setHeightUnits(int) */ @@ -411,8 +410,7 @@ public class Panel extends AbstractComponentContainer implements Sizeable, } /** - * Sets the width units. Panel supports only Sizeable.UNITS_PIXELS, and this - * is ignored. + * Sets the width units. * * @see com.itmill.toolkit.terminal.Sizeable#setWidthUnits(int) */ diff --git a/src/com/itmill/toolkit/ui/SplitPanel.java b/src/com/itmill/toolkit/ui/SplitPanel.java index a6db715e84..71a757eff5 100644 --- a/src/com/itmill/toolkit/ui/SplitPanel.java +++ b/src/com/itmill/toolkit/ui/SplitPanel.java @@ -214,7 +214,7 @@ public class SplitPanel extends AbstractComponentContainer implements Layout, Si target.addAttribute("width", "100%"); } if(height > 0) { - target.addAttribute("height", height + UNIT_SYMBOLS[widthUnit]); + target.addAttribute("height", height + UNIT_SYMBOLS[heightUnit]); } else { target.addAttribute("height", "100%"); } diff --git a/src/com/itmill/toolkit/ui/Table.java b/src/com/itmill/toolkit/ui/Table.java index 714f167ec5..ccc6405ca8 100644 --- a/src/com/itmill/toolkit/ui/Table.java +++ b/src/com/itmill/toolkit/ui/Table.java @@ -2372,14 +2372,11 @@ public class Table extends Select implements Action.Container, } /** - * Sets the height units. Table supports only Sizeable.UNITS_PIXELS. Setting - * to any other throws IllegalArgumentException. - * + * Sets the height units. + * * @see com.itmill.toolkit.terminal.Sizeable#setHeightUnits(int) */ public void setHeightUnits(int units) { - if (units != Sizeable.UNITS_PIXELS) - throw new IllegalArgumentException(); this.heightUnit = units; } -- 2.39.5