From 0628210c09a84b8468548283aa7b2eaf382dce26 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 26 Nov 2009 12:54:11 +0000 Subject: [PATCH] Fixed remaining issues for #3541 - VerticalLayout/GridLayout/AbsoluteLayout/CSSLayout should support click events svn changeset:10072/svn branch:6.2 --- src/com/vaadin/terminal/gwt/client/Util.java | 45 +++++++++++++ .../vaadin/terminal/gwt/client/VCaption.java | 17 +++++ .../gwt/client/ui/VAbsoluteLayout.java | 27 ++++---- .../terminal/gwt/client/ui/VCssLayout.java | 27 ++++++++ .../terminal/gwt/client/ui/VGridLayout.java | 25 ++++--- .../gwt/client/ui/VOrderedLayout.java | 21 ++---- src/com/vaadin/ui/AbsoluteLayout.java | 3 +- src/com/vaadin/ui/AbstractOrderedLayout.java | 3 +- src/com/vaadin/ui/CssLayout.java | 55 ++++++++++++++++ src/com/vaadin/ui/GridLayout.java | 3 +- .../layouts/TestLayoutClickListeners.html | 66 +++++++++++++++++-- .../layouts/TestLayoutClickListeners.java | 34 ++++++++++ 12 files changed, 274 insertions(+), 52 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index 9824b31e47..9ae18cc01d 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -755,4 +755,49 @@ public class Util { } + /** + * Locates the child component of parent which contains + * the element element. The child component is also + * returned if "element" is part of its caption. If + * element is not part of any child component, null is + * returned. + * + * @param client + * A reference to ApplicationConnection + * @param parent + * The widget that contains element. + * @param element + * An element that is a sub element of the parent + * @return The Paintable which the element is a part of. Null if the element + * does not belong to a child. + */ + public static Paintable getChildPaintableForElement( + ApplicationConnection client, Container parent, Element element) { + Element rootElement = ((Widget) parent).getElement(); + while (element != null && element != rootElement) { + Paintable paintable = client.getPaintable(element); + if (paintable == null) { + String ownerPid = VCaption.getCaptionOwnerPid(element); + if (ownerPid != null) { + paintable = client.getPaintable(ownerPid); + } + } + + if (paintable != null) { + try { + if (parent.hasChildComponent((Widget) paintable)) { + return paintable; + } + } catch (ClassCastException e) { + // We assume everything is a widget however there is no need + // to crash everything if there is a paintable that is not. + } + } + + element = (Element) element.getParentElement(); + } + + return null; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java index 5a6306b79b..ba57956c27 100644 --- a/src/com/vaadin/terminal/gwt/client/VCaption.java +++ b/src/com/vaadin/terminal/gwt/client/VCaption.java @@ -51,6 +51,9 @@ public class VCaption extends HTML { super(); this.client = client; owner = component; + + setOwnerPid(getElement(), client.getPid(owner)); + setStyleName(CLASSNAME); sinkEvents(VTooltip.TOOLTIP_EVENTS); @@ -440,4 +443,18 @@ public class VCaption extends HTML { return captionText; } + public static String getCaptionOwnerPid(Element e) { + return getOwnerPid(e); + } + + private native static void setOwnerPid(Element el, String pid) + /*-{ + el.vOwnerPid = pid; + }-*/; + + public native static String getOwnerPid(Element el) + /*-{ + return el.vOwnerPid; + }-*/; + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java index 63f865082b..2a7ee079a9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java @@ -24,6 +24,7 @@ import com.vaadin.terminal.gwt.client.Container; 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 { @@ -412,20 +413,18 @@ public class VAbsoluteLayout extends ComplexPanel implements Container { } } - private Paintable getComponent(Element target) { - while (target != null && target != canvas) { - Paintable paintable = client.getPaintable(target); - if (paintable != null) { - String pid = client.getPid(paintable); - AbsoluteWrapper wrapper = pidToComponentWrappper.get(pid); - if (wrapper != null) { - return paintable; - } - } - target = DOM.getParent(target); - } - - return null; + /** + * Returns the 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 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.getChildPaintableForElement(client, this, element); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java index ebd201724b..bf13530d7f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java @@ -10,6 +10,9 @@ import java.util.Iterator; import java.util.Set; 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.FlowPanel; @@ -22,17 +25,34 @@ import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.RenderSpace; import com.vaadin.terminal.gwt.client.StyleConstants; import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.ValueMap; public class VCssLayout extends SimplePanel implements Paintable, Container { public static final String TAGNAME = "csslayout"; public static final String CLASSNAME = "v-" + TAGNAME; + public static final String CLICK_EVENT_IDENTIFIER = "click"; private FlowPane panel = new FlowPane(); private Element margin = DOM.createDiv(); + private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( + this, CLICK_EVENT_IDENTIFIER) { + + @Override + protected Paintable getChildComponent(Element element) { + return panel.getComponent(element); + } + + @Override + protected HandlerRegistration registerHandler( + H handler, Type type) { + return addDomHandler(handler, type); + } + }; + private boolean hasHeight; private boolean hasWidth; @@ -68,6 +88,7 @@ public class VCssLayout extends SimplePanel implements Paintable, Container { if (client.updateComponent(this, uidl, true)) { return; } + clickEventHandler.handleEventHandlerRegistration(client); final VMarginInfo margins = new VMarginInfo(uidl .getIntAttribute("margins")); @@ -206,6 +227,12 @@ public class VCssLayout extends SimplePanel implements Paintable, Container { widgetToCaption.remove(component); } } + + private Paintable getComponent(Element element) { + return Util.getChildPaintableForElement(client, VCssLayout.this, + element); + } + } private RenderSpace space; diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java index 2dae5626d6..1c2fcf5b6f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java @@ -17,7 +17,6 @@ import com.google.gwt.dom.client.Document; 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.AbsolutePanel; import com.google.gwt.user.client.ui.SimplePanel; @@ -1044,20 +1043,18 @@ public class VGridLayout extends SimplePanel implements Paintable, Container { return cell; } + /** + * Returns the 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 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) { - Element rootElement = getElement(); - while (element != null && element != rootElement) { - Paintable paintable = client.getPaintable(element); - if (paintable != null) { - Cell cell = paintableToCell.get(paintable); - if (cell != null) { - return paintable; - } - } - element = DOM.getParent(element); - } - - return null; + return Util.getChildPaintableForElement(client, this, element); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java index cb5624142f..8848681753 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java @@ -938,24 +938,17 @@ public class VOrderedLayout extends CellBasedLayout { } /** - * Returns the child component which contains "element". + * Returns the child component which contains "element". The child component + * is also returned if "element" is part of its caption. * * @param element - * @return + * An element that is a 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) { - Element rootElement = getElement(); - while (element != null && element != rootElement) { - Paintable paintable = client.getPaintable(element); - if (paintable != null - && widgetToComponentContainer.containsKey(paintable)) { - return paintable; - } else { - element = (Element) element.getParentElement(); - } - } - - return null; + return Util.getChildPaintableForElement(client, this, element); } } diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java index d32ba913b1..406ee9072d 100644 --- a/src/com/vaadin/ui/AbsoluteLayout.java +++ b/src/com/vaadin/ui/AbsoluteLayout.java @@ -379,8 +379,7 @@ public class AbsoluteLayout extends AbstractLayout { * Add a click listener to the layout. The listener is called whenever the * user clicks inside the layout. Also when the click targets a component * inside the Panel, provided the targeted component does not prevent the - * click event from propagating. A caption is not considered part of a - * component. + * click event from propagating. * * The child component that was clicked is included in the * {@link LayoutClickEvent}. diff --git a/src/com/vaadin/ui/AbstractOrderedLayout.java b/src/com/vaadin/ui/AbstractOrderedLayout.java index dc722bbd12..04449bd7b8 100644 --- a/src/com/vaadin/ui/AbstractOrderedLayout.java +++ b/src/com/vaadin/ui/AbstractOrderedLayout.java @@ -334,8 +334,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements * Add a click listener to the layout. The listener is called whenever the * user clicks inside the layout. Also when the click targets a component * inside the Panel, provided the targeted component does not prevent the - * click event from propagating. A caption is not considered part of a - * component. + * click event from propagating. * * The child component that was clicked is included in the * {@link LayoutClickEvent}. diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java index 0b98ac7975..e027636956 100644 --- a/src/com/vaadin/ui/CssLayout.java +++ b/src/com/vaadin/ui/CssLayout.java @@ -3,10 +3,14 @@ package com.vaadin.ui; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.Map; +import com.vaadin.event.LayoutEvents.LayoutClickEvent; +import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Paintable; +import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.terminal.gwt.client.ui.VCssLayout; /** @@ -55,6 +59,8 @@ public class CssLayout extends AbstractLayout { private static final long serialVersionUID = -6408703812053460073L; + private static final String CLICK_EVENT = VCssLayout.CLICK_EVENT_IDENTIFIER; + /** * Custom layout slots containing the components. */ @@ -218,4 +224,53 @@ public class CssLayout extends AbstractLayout { } } + @Override + public void changeVariables(Object source, Map variables) { + super.changeVariables(source, variables); + + if (variables.containsKey(CLICK_EVENT)) { + fireClick((Map) variables.get(CLICK_EVENT)); + } + + } + + private void fireClick(Map parameters) { + MouseEventDetails mouseDetails = MouseEventDetails + .deSerialize((String) parameters.get("mouseDetails")); + Component childComponent = (Component) parameters.get("component"); + + fireEvent(new LayoutClickEvent(this, mouseDetails, childComponent)); + } + + /** + * Add a click listener to the layout. The listener is called whenever the + * user clicks inside the layout. Also when the click targets a component + * inside the Panel, provided the targeted component does not prevent the + * click event from propagating. A caption is not considered part of a + * component. + * + * The child component that was clicked is included in the + * {@link LayoutClickEvent}. + * + * Use {@link #removeListener(LayoutClickListener)} to remove the listener. + * + * @param listener + * The listener to add + */ + public void addListener(LayoutClickListener listener) { + addListener(CLICK_EVENT, LayoutClickEvent.class, listener, + LayoutClickListener.clickMethod); + } + + /** + * Remove a click listener from the layout. The listener should earlier have + * been added using {@link #addListener(LayoutClickListener)}. + * + * @param listener + * The listener to remove + */ + public void removeListener(LayoutClickListener listener) { + removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); + } + } diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java index 856565194c..778b9b42ca 100644 --- a/src/com/vaadin/ui/GridLayout.java +++ b/src/com/vaadin/ui/GridLayout.java @@ -1326,8 +1326,7 @@ public class GridLayout extends AbstractLayout implements * Add a click listener to the layout. The listener is called whenever the * user clicks inside the layout. Also when the click targets a component * inside the Panel, provided the targeted component does not prevent the - * click event from propagating. A caption is not considered part of a - * component. + * click event from propagating. * * The child component that was clicked is included in the * {@link LayoutClickEvent}. diff --git a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.html b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.html index aa2e923ffa..f488eb9a81 100644 --- a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.html +++ b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.html @@ -26,6 +26,7 @@ initial + mouseClick vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VLabel[0] @@ -56,6 +57,22 @@ vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] exact:GridLayout: Click on This is tf5 + + mouseClick + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/domChild[0]/domChild[0]/domChild[1] + 87,42 + + + waitForVaadin + + + + + assertText + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] + exact:GridLayout: Click on <none> + + mouseClick vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0] @@ -86,6 +103,7 @@ vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] exact:VerticalLayout: Click on This is label 3 + click vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VAbsoluteLayout[0]/VAbsoluteLayout$AbsoluteWrapper[2]/VButton[0]/domChild[0]/domChild[0] @@ -121,22 +139,62 @@ vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] exact:AbsoluteLayout: Click on This is its caption + + + waitForVaadin + + + mouseClick - vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/domChild[0]/domChild[0]/domChild[1] - 87,42 + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[3]/VCssLayout[0]/VCssLayout$FlowPane[0]/VTextField[0] + 108,13 waitForVaadin + + mouseClick + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[3]/VCssLayout[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0] + 76,12 + + + waitForVaadin + + + + + assertText + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0] + exact:CSSLayout: Click on This is its caption + assertText vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] - exact:GridLayout: Click on <none> + exact:CSSLayout: Click on This is its caption + + + click + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[3]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[0]/domChild[0]/domChild[0] + + + + waitForVaadin + + + + + assertText + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0] + Button A button with its own click listener was clicked + + + assertText + vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] + exact:CSSLayout: Click on A button with its own click listener - diff --git a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java index a96404e4f6..ecda096690 100644 --- a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java +++ b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java @@ -9,6 +9,7 @@ import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.AbsoluteLayout; import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.CssLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; @@ -69,6 +70,7 @@ public class TestLayoutClickListeners extends AbstractTestCase { layoutsLayout.addComponent(createClickableGridLayout()); layoutsLayout.addComponent(createClickableVerticalLayout()); layoutsLayout.addComponent(createClickableAbsoluteLayout()); + layoutsLayout.addComponent(createClickableCSSLayout()); VerticalLayout mainLayout = new VerticalLayout(); mainLayout.setMargin(true); @@ -111,6 +113,38 @@ public class TestLayoutClickListeners extends AbstractTestCase { } + private Component createClickableCSSLayout() { + final CssLayout cl = new CssLayout(); + cl.setCaption("CSSLayout"); + cl.setStyleName("borders"); + cl.setWidth("300px"); + cl.setHeight("500px"); + cl.addComponent(new TextField("This is its caption", + "This is a textfield")); + cl.addComponent(new TextField("Another textfield caption", + "This is another textfield")); + + cl.addComponent(new Button("A button with its own click listener", + new Button.ClickListener() { + + public void buttonClick( + com.vaadin.ui.Button.ClickEvent event) { + log.log("Button " + event.getButton().getCaption() + + " was clicked"); + + } + })); + cl.addListener(new LayoutClickListener() { + + public void layoutClick(LayoutClickEvent event) { + logLayoutClick("CSSLayout", event.getChildComponent()); + } + }); + + return cl; + + } + private Layout createClickableGridLayout() { GridLayout gl = new GridLayout(4, 4); -- 2.39.5