Browse Source

Allow defining a focus delegate component for CustomField (#20336)

Change-Id: I1160e7a384b1816204eb7f4b0f52f83ed9e230c0
tags/7.7.4
Artur Signell 7 years ago
parent
commit
44603b49f8

+ 59
- 0
client/src/main/java/com/vaadin/client/ui/VCustomField.java View File

@@ -0,0 +1,59 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.client.ui;

import com.vaadin.client.Focusable;

public class VCustomField extends VCustomComponent implements Focusable {

private Focusable focusDelegate;

@Override
public void focus() {
if (focusDelegate != null) {
focusDelegate.focus();
}
}

/**
* Sets the focusable widget to focus instead of this custom field.
*
* @param focusDelegate
* the widget to delegate focus to
*/
public void setFocusDelegate(Focusable focusDelegate) {
this.focusDelegate = focusDelegate;

}

/**
* Sets the focusable widget to focus instead of this custom field.
*
* @param focusDelegate
* the widget to delegate focus to
*/
public void setFocusDelegate(
final com.google.gwt.user.client.ui.Focusable focusDelegate) {
this.focusDelegate = new Focusable() {
@Override
public void focus() {
focusDelegate.setFocus(true);
}
};

}

}

+ 38
- 3
client/src/main/java/com/vaadin/client/ui/customfield/CustomFieldConnector.java View File

@@ -17,16 +17,20 @@ package com.vaadin.client.ui.customfield;

import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
import com.vaadin.client.Focusable;
import com.vaadin.client.HasComponentsConnector;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.VCustomComponent;
import com.vaadin.client.ui.VCustomField;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.customfield.CustomFieldState;
import com.vaadin.ui.CustomField;

@Connect(value = CustomField.class)
@@ -43,8 +47,13 @@ public class CustomFieldConnector extends AbstractFieldConnector
}

@Override
public VCustomComponent getWidget() {
return (VCustomComponent) super.getWidget();
public CustomFieldState getState() {
return (CustomFieldState) super.getState();
}

@Override
public VCustomField getWidget() {
return (VCustomField) super.getWidget();
}

@Override
@@ -52,6 +61,32 @@ public class CustomFieldConnector extends AbstractFieldConnector
// NOP, custom field does not render the caption of its content
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
if (getState().focusDelegate != null) {
Widget widget = ((ComponentConnector) getState().focusDelegate)
.getWidget();
if (widget instanceof Focusable) {
getWidget().setFocusDelegate((Focusable) widget);
} else if (widget instanceof com.google.gwt.user.client.ui.Focusable) {
getWidget().setFocusDelegate(
(com.google.gwt.user.client.ui.Focusable) widget);
} else {
getLogger().warning(
"The given focus delegate does not implement Focusable: "
+ widget.getClass().getName());
}
} else {
getWidget().setFocusDelegate((Focusable) null);
}

}

private static Logger getLogger() {
return Logger.getLogger(CustomFieldConnector.class.getName());
}

@Override
public void onConnectorHierarchyChange(
ConnectorHierarchyChangeEvent event) {

+ 61
- 0
server/src/main/java/com/vaadin/ui/CustomField.java View File

@@ -20,6 +20,7 @@ import java.io.Serializable;
import java.util.Iterator;

import com.vaadin.data.Property;
import com.vaadin.shared.ui.customfield.CustomFieldState;

/**
* A {@link Field} whose UI content can be constructed by the user, enabling the
@@ -150,4 +151,64 @@ public abstract class CustomField<T> extends AbstractField<T>
public Iterator<Component> iterator() {
return new ComponentIterator();
}

@Override
protected CustomFieldState getState() {
return (CustomFieldState) super.getState();
}

@Override
protected CustomFieldState getState(boolean markAsDirty) {
return (CustomFieldState) super.getState(markAsDirty);
}

/**
* Sets the component to which all methods from the {@link Focusable}
* interface should be delegated.
* <p>
* Set this to a wrapped field to include that field in the tabbing order,
* to make it receive focus when {@link #focus()} is called and to make it
* be correctly focused when used as a Grid editor component.
* <p>
* By default, {@link Focusable} events are handled by the super class and
* ultimately ignored.
*
* @param focusDelegate
* the focusable component to which focus events are redirected
*/
public void setFocusDelegate(Focusable focusDelegate) {
getState().focusDelegate = focusDelegate;
}

private Focusable getFocusable() {
return (Focusable) getState(false).focusDelegate;
}

@Override
public void focus() {
if (getFocusable() != null) {
getFocusable().focus();
} else {
super.focus();
}
}

@Override
public int getTabIndex() {
if (getFocusable() != null) {
return getFocusable().getTabIndex();
} else {
return super.getTabIndex();
}
}

@Override
public void setTabIndex(int tabIndex) {
if (getFocusable() != null) {
getFocusable().setTabIndex(tabIndex);
} else {
super.setTabIndex(tabIndex);
}
}

}

+ 29
- 0
shared/src/main/java/com/vaadin/shared/ui/customfield/CustomFieldState.java View File

@@ -0,0 +1,29 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.shared.ui.customfield;

import com.vaadin.shared.AbstractFieldState;
import com.vaadin.shared.Connector;

public class CustomFieldState extends AbstractFieldState {

/**
* The component which should receive focus events instead of the custom
* field wrapper.
*/
public Connector focusDelegate;

}

+ 2
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditorCustomField.java View File

@@ -73,6 +73,8 @@ public class GridEditorCustomField extends AbstractTestUIWithLog {
Button addCountryButton = new Button("New");
fieldLayout.addComponent(addCountryButton);

setFocusDelegate(cityComboBox);

return fieldLayout;
}


+ 16
- 1
uitest/src/test/java/com/vaadin/tests/components/grid/GridEditorCustomFieldTest.java View File

@@ -17,13 +17,14 @@ package com.vaadin.tests.components.grid;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.Keys;

import com.vaadin.testbench.TestBenchElement;
import com.vaadin.testbench.elements.ComboBoxElement;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.GridElement.GridEditorElement;
import com.vaadin.testbench.parallel.TestCategory;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

@TestCategory("grid")
public class GridEditorCustomFieldTest extends MultiBrowserTest {
@@ -43,4 +44,18 @@ public class GridEditorCustomFieldTest extends MultiBrowserTest {
Assert.assertEquals("Oslo", grid.getCell(0, 2).getText());

}

@Test
public void tabReachesCustomField() {
openTestURL();
GridElement grid = $(GridElement.class).first();
grid.getCell(0, 1).doubleClick();
GridEditorElement editor = grid.getEditor();
editor.getField(0).sendKeys(Keys.TAB, Keys.TAB);

ComboBoxElement comboBoxInCustomField = editor.getField(2)
.$(ComboBoxElement.class).first();
assertElementsEquals(comboBoxInCustomField.getInputField(),
getActiveElement());
}
}

Loading…
Cancel
Save