Change-Id: I1160e7a384b1816204eb7f4b0f52f83ed9e230c0tags/7.7.4
/* | |||||
* 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); | |||||
} | |||||
}; | |||||
} | |||||
} |
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.logging.Logger; | |||||
import com.google.gwt.event.shared.HandlerRegistration; | import com.google.gwt.event.shared.HandlerRegistration; | ||||
import com.google.gwt.user.client.ui.Widget; | import com.google.gwt.user.client.ui.Widget; | ||||
import com.vaadin.client.ComponentConnector; | import com.vaadin.client.ComponentConnector; | ||||
import com.vaadin.client.ConnectorHierarchyChangeEvent; | import com.vaadin.client.ConnectorHierarchyChangeEvent; | ||||
import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler; | import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler; | ||||
import com.vaadin.client.Focusable; | |||||
import com.vaadin.client.HasComponentsConnector; | import com.vaadin.client.HasComponentsConnector; | ||||
import com.vaadin.client.communication.StateChangeEvent; | |||||
import com.vaadin.client.ui.AbstractFieldConnector; | 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.Connect; | ||||
import com.vaadin.shared.ui.customfield.CustomFieldState; | |||||
import com.vaadin.ui.CustomField; | import com.vaadin.ui.CustomField; | ||||
@Connect(value = CustomField.class) | @Connect(value = CustomField.class) | ||||
} | } | ||||
@Override | @Override | ||||
public VCustomComponent getWidget() { | |||||
return (VCustomComponent) super.getWidget(); | |||||
public CustomFieldState getState() { | |||||
return (CustomFieldState) super.getState(); | |||||
} | |||||
@Override | |||||
public VCustomField getWidget() { | |||||
return (VCustomField) super.getWidget(); | |||||
} | } | ||||
@Override | @Override | ||||
// NOP, custom field does not render the caption of its content | // 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 | @Override | ||||
public void onConnectorHierarchyChange( | public void onConnectorHierarchyChange( | ||||
ConnectorHierarchyChangeEvent event) { | ConnectorHierarchyChangeEvent event) { |
import java.util.Iterator; | import java.util.Iterator; | ||||
import com.vaadin.data.Property; | 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 | * A {@link Field} whose UI content can be constructed by the user, enabling the | ||||
public Iterator<Component> iterator() { | public Iterator<Component> iterator() { | ||||
return new ComponentIterator(); | 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); | |||||
} | |||||
} | |||||
} | } |
/* | |||||
* 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; | |||||
} |
Button addCountryButton = new Button("New"); | Button addCountryButton = new Button("New"); | ||||
fieldLayout.addComponent(addCountryButton); | fieldLayout.addComponent(addCountryButton); | ||||
setFocusDelegate(cityComboBox); | |||||
return fieldLayout; | return fieldLayout; | ||||
} | } | ||||
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.openqa.selenium.Keys; | |||||
import com.vaadin.testbench.TestBenchElement; | import com.vaadin.testbench.TestBenchElement; | ||||
import com.vaadin.testbench.elements.ComboBoxElement; | |||||
import com.vaadin.testbench.elements.GridElement; | import com.vaadin.testbench.elements.GridElement; | ||||
import com.vaadin.testbench.elements.GridElement.GridEditorElement; | import com.vaadin.testbench.elements.GridElement.GridEditorElement; | ||||
import com.vaadin.testbench.parallel.TestCategory; | import com.vaadin.testbench.parallel.TestCategory; | ||||
import com.vaadin.tests.tb3.MultiBrowserTest; | import com.vaadin.tests.tb3.MultiBrowserTest; | ||||
import com.vaadin.tests.tb3.newelements.ComboBoxElement; | |||||
@TestCategory("grid") | @TestCategory("grid") | ||||
public class GridEditorCustomFieldTest extends MultiBrowserTest { | public class GridEditorCustomFieldTest extends MultiBrowserTest { | ||||
Assert.assertEquals("Oslo", grid.getCell(0, 2).getText()); | 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()); | |||||
} | |||||
} | } |