Author: [email protected]
Date: Tue Mar 10 17:16:05 2009
New Revision: 4978
Modified:
releases/1.6/user/src/com/google/gwt/user/client/ui/CheckBox.java
releases/1.6/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
Log:
Fixes issue 3454, "RadioButtons fire ValueChangeEvents when clicked
even when value does not change"
Reviewed by jgw
Modified: releases/1.6/user/src/com/google/gwt/user/client/ui/CheckBox.java
==============================================================================
--- releases/1.6/user/src/com/google/gwt/user/client/ui/CheckBox.java
(original)
+++ releases/1.6/user/src/com/google/gwt/user/client/ui/CheckBox.java Tue
Mar 10 17:16:05 2009
@@ -20,6 +20,10 @@
import com.google.gwt.dom.client.LabelElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -55,6 +59,7 @@
private InputElement inputElem;
private LabelElement labelElem;
private boolean valueChangeHandlerInitialized;
+ private boolean valueBeforeClick;
/**
* Creates a check box with no label.
@@ -111,17 +116,29 @@
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<Boolean> handler) {
- // Is this the first value change handler? If so, time to listen to
clicks
- // on the checkbox
+ // Is this the first value change handler? If so, time to add handlers
if (!valueChangeHandlerInitialized) {
- valueChangeHandlerInitialized = true;
+
+ this.addKeyUpHandler(new KeyUpHandler() {
+ public void onKeyUp(KeyUpEvent event) {
+ valueBeforeClick = getValue();
+ }
+ });
+
+ this.addMouseUpHandler(new MouseUpHandler() {
+ public void onMouseUp(MouseUpEvent event) {
+ valueBeforeClick = getValue();
+ }
+ });
+
this.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
- // No need to compare old value and new value--click handler
- // only fires on real click, and value always toggles
- ValueChangeEvent.fire(CheckBox.this, getValue());
+ ValueChangeEvent.fireIfNotEqual(CheckBox.this, valueBeforeClick,
+ getValue());
}
});
+
+ valueChangeHandlerInitialized = true;
}
return addHandler(handler, ValueChangeEvent.getType());
}
@@ -312,13 +329,15 @@
}
}
- // Unlike other widgets the CheckBox sinks on its input element, not its
- // wrapper element.
+ // Unlike other widgets the CheckBox sinks on its constituent elements,
not
+ // their wrapper element.
@Override
public void sinkEvents(int eventBitsToAdd) {
if (isOrWasAttached()) {
Event.sinkEvents(inputElem,
eventBitsToAdd | Event.getEventsSunk(inputElem));
+ Event.sinkEvents(labelElem,
+ eventBitsToAdd | Event.getEventsSunk(labelElem));
} else {
super.sinkEvents(eventBitsToAdd);
}
Modified:
releases/1.6/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
==============================================================================
---
releases/1.6/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
(original)
+++
releases/1.6/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
Tue Mar 10 17:16:05 2009
@@ -15,15 +15,28 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.dom.client.LabelElement;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
/**
* Tests the RadioButton class.
*/
public class RadioButtonTest extends GWTTestCase {
+ private static class Changeable implements ValueChangeHandler<Boolean> {
+ Boolean received;
+ public void onValueChange(ValueChangeEvent<Boolean> event) {
+ received = event.getValue();
+ }
+ }
+
@Override
public String getModuleName() {
return "com.google.gwt.user.DebugTest";
@@ -33,7 +46,7 @@
RadioButton radio = new RadioButton("myName", "myLabel");
// We need to replace the input element so we can keep a handle to it
- Element newInput = DOM.createInputRadio("MyName");
+ com.google.gwt.user.client.Element newInput =
DOM.createInputRadio("MyName");
radio.replaceInputElement(newInput);
radio.ensureDebugId("myRadio");
@@ -43,7 +56,40 @@
UIObjectTest.assertDebugId("myRadio-input", newInput);
UIObjectTest.assertDebugIdContents("myRadio-label", "myLabel");
}
+
+ /**
+ * Test the name and grouping methods.
+ */
+ public void testGrouping() {
+ // Create some radio buttons
+ RadioButton r1 = new RadioButton("group1", "Radio 1");
+ RadioButton r2 = new RadioButton("group1", "Radio 2");
+ RadioButton r3 = new RadioButton("group2", "Radio 3");
+ RootPanel.get().add(r1);
+ RootPanel.get().add(r2);
+ RootPanel.get().add(r3);
+
+ // Check one button in each group
+ r2.setValue(true);
+ r3.setValue(true);
+ // Move a button over
+ r2.setName("group2");
+
+ // Check that the correct buttons are checked
+ assertTrue(r2.getValue());
+ assertFalse(r3.getValue());
+
+ r1.setValue(true);
+ assertTrue(r1.getValue());
+ assertTrue(r2.getValue());
+
+ r3.setValue(true);
+ assertTrue(r1.getValue());
+ assertFalse(r2.getValue());
+ assertTrue(r3.getValue());
+ }
+
/**
* Test the name and grouping methods via deprecated calls.
*/
@@ -78,36 +124,107 @@
assertTrue(r3.isChecked());
}
- /**
- * Test the name and grouping methods.
- */
- public void testGrouping() {
- // Create some radio buttons
+ public void testValueChangeViaClick() {
RadioButton r1 = new RadioButton("group1", "Radio 1");
RadioButton r2 = new RadioButton("group1", "Radio 2");
- RadioButton r3 = new RadioButton("group2", "Radio 3");
RootPanel.get().add(r1);
RootPanel.get().add(r2);
- RootPanel.get().add(r3);
+ r1.setValue(true);
+
+ Changeable c1 = new Changeable();
+ r1.addValueChangeHandler(c1);
+
+ Changeable c2 = new Changeable();
+ r2.addValueChangeHandler(c2);
+
+ // Brittle, but there's no public access
+ InputElement r1Radio = getRadioElement(r1);
+ InputElement r2Radio = getRadioElement(r2);
+
+ doClick(r1Radio);
+ assertEquals(null, c1.received);
+ assertEquals(null, c2.received);
+
+ doClick(r2Radio);
+ assertEquals(null, c1.received);
+ assertEquals(Boolean.TRUE, c2.received);
+ c2.received = null;
+
+ doClick(r1Radio);
+ assertEquals(Boolean.TRUE, c1.received);
+ assertEquals(null, c2.received);
+ }
- // Check one button in each group
- r2.setValue(true);
- r3.setValue(true);
+ public void testValueChangeViaLabelClick() {
+ RadioButton r1 = new RadioButton("group1", "Radio 1");
+ RadioButton r2 = new RadioButton("group1", "Radio 2");
+ RootPanel.get().add(r1);
+ RootPanel.get().add(r2);
+ r1.setValue(true);
+
+ Changeable c1 = new Changeable();
+ r1.addValueChangeHandler(c1);
+
+ Changeable c2 = new Changeable();
+ r2.addValueChangeHandler(c2);
+
+ LabelElement r1Label = getLabelElement(r1);
+ LabelElement r2Label = getLabelElement(r2);
+
+ doClick(r1Label);
+ assertEquals(null, c1.received);
+ assertEquals(null, c2.received);
+
+ doClick(r2Label);
+ assertEquals(null, c1.received);
+ assertEquals(Boolean.TRUE, c2.received);
+ c2.received = null;
+
+ doClick(r1Label);
+ assertEquals(Boolean.TRUE, c1.received);
+ assertEquals(null, c2.received);
+ }
- // Move a button over
- r2.setName("group2");
+ private void doClick(Element elm) {
+ NativeEvent e =
+ Document.get().createMouseDownEvent(0, 25, 25, 25, 25, false,
false,
+ false, false, NativeEvent.BUTTON_LEFT);
+ elm.dispatchEvent(e);
+
+ e = Document.get().createMouseUpEvent(0, 25, 25, 25, 25, false, false,
+ false, false, NativeEvent.BUTTON_LEFT);
+ elm.dispatchEvent(e);
+
+ e = Document.get().createClickEvent(0, 25, 25, 25, 25, false, false,
false,
+ false);
+ elm.dispatchEvent(e);
+ }
- // Check that the correct buttons are checked
- assertTrue(r2.getValue());
- assertFalse(r3.getValue());
+ private void doSpacebar(Element elm) {
+ NativeEvent e =
+ Document.get().createFocusEvent();
+ elm.dispatchEvent(e);
- r1.setValue(true);
- assertTrue(r1.getValue());
- assertTrue(r2.getValue());
+ e = Document.get().createKeyDownEvent(false, false, false, false, 32,
32);
+ elm.dispatchEvent(e);
- r3.setValue(true);
- assertTrue(r1.getValue());
- assertFalse(r2.getValue());
- assertTrue(r3.getValue());
+ e = Document.get().createKeyPressEvent(false, false, false, false, 32,
32);
+ elm.dispatchEvent(e);
+
+ e = Document.get().createKeyUpEvent(false, false, false, false, 32,
32);
+ elm.dispatchEvent(e);
+ }
+
+ private LabelElement getLabelElement(RadioButton radioButton) {
+ LabelElement r1Label =
+ LabelElement.as(Element.as(getRadioElement(radioButton)
+ .getNextSiblingElement()));
+ return r1Label;
+ }
+
+ private InputElement getRadioElement(RadioButton radioButton) {
+ InputElement r1Radio =
+
InputElement.as(Element.as(radioButton.getElement().getFirstChild()));
+ return r1Radio;
}
}
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---