Change-Id: Id187402e78e3c368ae6530f7b7ea68d2e6c4a6catags/8.0.0.alpha3
@@ -0,0 +1,141 @@ | |||
/* | |||
* Copyright 2000-2016 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.v7.client.ui; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.event.dom.client.KeyDownEvent; | |||
import com.google.gwt.event.dom.client.KeyDownHandler; | |||
import com.google.gwt.event.shared.HandlerRegistration; | |||
import com.google.gwt.user.client.DOM; | |||
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.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.VErrorMessage; | |||
import com.vaadin.client.ui.Icon; | |||
import com.vaadin.client.ui.ShortcutActionHandler; | |||
public class VForm extends ComplexPanel implements KeyDownHandler { | |||
public static final String CLASSNAME = "v-form"; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public String id; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Widget lo; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element legend = DOM.createLegend(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element caption = DOM.createSpan(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element desc = DOM.createDiv(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Icon icon; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public VErrorMessage errorMessage = new VErrorMessage(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element fieldContainer = DOM.createDiv(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element footerContainer = DOM.createDiv(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Element fieldSet = DOM.createFieldSet(); | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Widget footer; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public ApplicationConnection client; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public ShortcutActionHandler shortcutHandler; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public HandlerRegistration keyDownRegistration; | |||
public VForm() { | |||
setElement(DOM.createDiv()); | |||
getElement().appendChild(fieldSet); | |||
setStyleName(CLASSNAME); | |||
fieldSet.appendChild(legend); | |||
legend.appendChild(caption); | |||
fieldSet.appendChild(desc); // Adding description for initial padding | |||
// measurements, removed later if no | |||
// description is set | |||
fieldSet.appendChild(fieldContainer); | |||
errorMessage.setVisible(false); | |||
fieldSet.appendChild(errorMessage.getElement()); | |||
fieldSet.appendChild(footerContainer); | |||
errorMessage.setOwner(this); | |||
} | |||
@Override | |||
public void setStyleName(String style) { | |||
super.setStyleName(style); | |||
updateStyleNames(); | |||
} | |||
@Override | |||
public void setStylePrimaryName(String style) { | |||
super.setStylePrimaryName(style); | |||
updateStyleNames(); | |||
} | |||
protected void updateStyleNames() { | |||
fieldContainer.setClassName(getStylePrimaryName() + "-content"); | |||
errorMessage.setStyleName(getStylePrimaryName() + "-errormessage"); | |||
desc.setClassName(getStylePrimaryName() + "-description"); | |||
footerContainer.setClassName(getStylePrimaryName() + "-footer"); | |||
} | |||
@Override | |||
public void onKeyDown(KeyDownEvent event) { | |||
shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent())); | |||
} | |||
public void setFooterWidget(Widget footerWidget) { | |||
if (footer != null) { | |||
remove(footer); | |||
} | |||
if (footerWidget != null) { | |||
super.add(footerWidget, footerContainer); | |||
} | |||
footer = footerWidget; | |||
} | |||
public void setLayoutWidget(Widget newLayoutWidget) { | |||
if (lo != null) { | |||
remove(lo); | |||
} | |||
if (newLayoutWidget != null) { | |||
super.add(newLayoutWidget, fieldContainer); | |||
} | |||
lo = newLayoutWidget; | |||
} | |||
} |
@@ -0,0 +1,236 @@ | |||
/* | |||
* Copyright 2000-2016 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.v7.client.ui.form; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.Style.Unit; | |||
import com.google.gwt.event.dom.client.KeyDownEvent; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.ComponentConnector; | |||
import com.vaadin.client.ConnectorHierarchyChangeEvent; | |||
import com.vaadin.client.LayoutManager; | |||
import com.vaadin.client.Paintable; | |||
import com.vaadin.client.TooltipInfo; | |||
import com.vaadin.client.UIDL; | |||
import com.vaadin.client.VCaption; | |||
import com.vaadin.client.ui.AbstractComponentContainerConnector; | |||
import com.vaadin.client.ui.ShortcutActionHandler; | |||
import com.vaadin.client.ui.layout.ElementResizeEvent; | |||
import com.vaadin.client.ui.layout.ElementResizeListener; | |||
import com.vaadin.client.ui.layout.MayScrollChildren; | |||
import com.vaadin.shared.ui.ComponentStateUtil; | |||
import com.vaadin.shared.ui.Connect; | |||
import com.vaadin.v7.client.ui.VForm; | |||
import com.vaadin.v7.shared.form.FormState; | |||
import com.vaadin.v7.ui.Form; | |||
@Connect(Form.class) | |||
public class FormConnector extends AbstractComponentContainerConnector | |||
implements Paintable, MayScrollChildren { | |||
private final ElementResizeListener footerResizeListener = new ElementResizeListener() { | |||
@Override | |||
public void onElementResize(ElementResizeEvent e) { | |||
com.vaadin.v7.client.ui.VForm form = getWidget(); | |||
LayoutManager lm = getLayoutManager(); | |||
int footerHeight = 0; | |||
if (form.footer != null) { | |||
footerHeight += lm.getOuterHeight(form.footer.getElement()); | |||
} | |||
if (form.errorMessage.isVisible()) { | |||
footerHeight += lm | |||
.getOuterHeight(form.errorMessage.getElement()); | |||
footerHeight -= lm.getMarginTop(form.errorMessage.getElement()); | |||
form.errorMessage.getElement().getStyle() | |||
.setMarginTop(-footerHeight, Unit.PX); | |||
form.footerContainer.getStyle().clearMarginTop(); | |||
} else { | |||
form.footerContainer.getStyle().setMarginTop(-footerHeight, | |||
Unit.PX); | |||
} | |||
form.fieldContainer.getStyle().setPaddingBottom(footerHeight, | |||
Unit.PX); | |||
} | |||
}; | |||
@Override | |||
protected void init() { | |||
getLayoutManager().addElementResizeListener( | |||
getWidget().errorMessage.getElement(), footerResizeListener); | |||
} | |||
@Override | |||
public void onUnregister() { | |||
VForm form = getWidget(); | |||
getLayoutManager().removeElementResizeListener( | |||
form.errorMessage.getElement(), footerResizeListener); | |||
if (form.footer != null) { | |||
getLayoutManager().removeElementResizeListener( | |||
form.footer.getElement(), footerResizeListener); | |||
} | |||
} | |||
@Override | |||
public boolean delegateCaptionHandling() { | |||
return false; | |||
} | |||
@Override | |||
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { | |||
getWidget().client = client; | |||
getWidget().id = uidl.getId(); | |||
if (!isRealUpdate(uidl)) { | |||
return; | |||
} | |||
boolean legendEmpty = true; | |||
if (getState().caption != null) { | |||
VCaption.setCaptionText(getWidget().caption, getState()); | |||
legendEmpty = false; | |||
} else { | |||
getWidget().caption.setInnerText(""); | |||
} | |||
if (getWidget().icon != null) { | |||
getWidget().legend.removeChild(getWidget().icon.getElement()); | |||
} | |||
if (getIconUri() != null) { | |||
getWidget().icon = client.getIcon(getIconUri()); | |||
getWidget().legend.insertFirst(getWidget().icon.getElement()); | |||
legendEmpty = false; | |||
} | |||
if (legendEmpty) { | |||
getWidget().addStyleDependentName("nocaption"); | |||
} else { | |||
getWidget().removeStyleDependentName("nocaption"); | |||
} | |||
if (null != getState().errorMessage) { | |||
getWidget().errorMessage.updateMessage(getState().errorMessage); | |||
getWidget().errorMessage.setVisible(true); | |||
} else { | |||
getWidget().errorMessage.setVisible(false); | |||
} | |||
if (ComponentStateUtil.hasDescription(getState())) { | |||
getWidget().desc.setInnerHTML(getState().description); | |||
if (getWidget().desc.getParentElement() == null) { | |||
getWidget().fieldSet.insertAfter(getWidget().desc, | |||
getWidget().legend); | |||
} | |||
} else { | |||
getWidget().desc.setInnerHTML(""); | |||
if (getWidget().desc.getParentElement() != null) { | |||
getWidget().fieldSet.removeChild(getWidget().desc); | |||
} | |||
} | |||
// also recalculates size of the footer if undefined size form - see | |||
// #3710 | |||
client.runDescendentsLayout(getWidget()); | |||
// We may have actions attached | |||
if (uidl.getChildCount() >= 1) { | |||
UIDL childUidl = uidl.getChildByTagName("actions"); | |||
if (childUidl != null) { | |||
if (getWidget().shortcutHandler == null) { | |||
getWidget().shortcutHandler = new ShortcutActionHandler( | |||
getConnectorId(), client); | |||
getWidget().keyDownRegistration = getWidget() | |||
.addDomHandler(getWidget(), KeyDownEvent.getType()); | |||
} | |||
getWidget().shortcutHandler.updateActionMap(childUidl); | |||
} | |||
} else if (getWidget().shortcutHandler != null) { | |||
getWidget().keyDownRegistration.removeHandler(); | |||
getWidget().shortcutHandler = null; | |||
getWidget().keyDownRegistration = null; | |||
} | |||
} | |||
@Override | |||
public void updateCaption(ComponentConnector component) { | |||
// NOP form don't render caption for neither field layout nor footer | |||
// layout | |||
} | |||
@Override | |||
public VForm getWidget() { | |||
return (VForm) super.getWidget(); | |||
} | |||
@Override | |||
public boolean isReadOnly() { | |||
return super.isReadOnly() || getState().propertyReadOnly; | |||
} | |||
@Override | |||
public FormState getState() { | |||
return (FormState) super.getState(); | |||
} | |||
private ComponentConnector getFooter() { | |||
return (ComponentConnector) getState().footer; | |||
} | |||
private ComponentConnector getLayout() { | |||
return (ComponentConnector) getState().layout; | |||
} | |||
@Override | |||
public void onConnectorHierarchyChange( | |||
ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { | |||
Widget newFooterWidget = null; | |||
ComponentConnector footer = getFooter(); | |||
if (footer != null) { | |||
newFooterWidget = footer.getWidget(); | |||
Widget currentFooter = getWidget().footer; | |||
if (currentFooter != null) { | |||
// Remove old listener | |||
getLayoutManager().removeElementResizeListener( | |||
currentFooter.getElement(), footerResizeListener); | |||
} | |||
getLayoutManager().addElementResizeListener( | |||
newFooterWidget.getElement(), footerResizeListener); | |||
} | |||
getWidget().setFooterWidget(newFooterWidget); | |||
Widget newLayoutWidget = null; | |||
ComponentConnector newLayout = getLayout(); | |||
if (newLayout != null) { | |||
newLayoutWidget = newLayout.getWidget(); | |||
} | |||
getWidget().setLayoutWidget(newLayoutWidget); | |||
} | |||
@Override | |||
public TooltipInfo getTooltipInfo(Element element) { | |||
// Form shows its description and error message | |||
// as a part of the actual layout | |||
return null; | |||
} | |||
@Override | |||
public boolean hasTooltip() { | |||
return false; | |||
} | |||
} |
@@ -18,6 +18,7 @@ package com.vaadin.v7.ui; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Calendar; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
import java.util.Locale; | |||
@@ -71,7 +72,7 @@ public class DateField extends AbstractField<Date> implements | |||
/** | |||
* Resolution identifier: seconds. | |||
* | |||
* | |||
* @deprecated As of 7.0, use {@link Resolution#SECOND} | |||
*/ | |||
@Deprecated | |||
@@ -600,6 +601,16 @@ public class DateField extends AbstractField<Date> implements | |||
fireValueChange(false); | |||
} | |||
/* | |||
* Because of our custom implementation of isValid(), that | |||
* also checks the parsingSucceeded flag, we must also | |||
* notify the form (if this is used in one) that the | |||
* validity of this field has changed. | |||
* | |||
* Normally fields validity doesn't change without value | |||
* change and form depends on this implementation detail. | |||
*/ | |||
notifyFormOfValidityChange(); | |||
markAsDirty(); | |||
} | |||
} else if (newDate != oldDate | |||
@@ -693,6 +704,38 @@ public class DateField extends AbstractField<Date> implements | |||
super.setValue(newValue, repaintIsNotNeeded); | |||
} | |||
/** | |||
* Detects if this field is used in a Form (logically) and if so, notifies | |||
* it (by repainting it) that the validity of this field might have changed. | |||
*/ | |||
private void notifyFormOfValidityChange() { | |||
Component parenOfDateField = getParent(); | |||
boolean formFound = false; | |||
while (parenOfDateField != null || formFound) { | |||
if (parenOfDateField instanceof Form) { | |||
Form f = (Form) parenOfDateField; | |||
Collection<?> visibleItemProperties = f.getItemPropertyIds(); | |||
for (Object fieldId : visibleItemProperties) { | |||
Field<?> field = f.getField(fieldId); | |||
if (equals(field)) { | |||
/* | |||
* this datefield is logically in a form. Do the same | |||
* thing as form does in its value change listener that | |||
* it registers to all fields. | |||
*/ | |||
f.markAsDirty(); | |||
formFound = true; | |||
break; | |||
} | |||
} | |||
} | |||
if (formFound) { | |||
break; | |||
} | |||
parenOfDateField = parenOfDateField.getParent(); | |||
} | |||
} | |||
@Override | |||
protected void setInternalValue(Date newValue) { | |||
// Also set the internal dateString |
@@ -1,12 +1,12 @@ | |||
/* | |||
* Copyright 2000-2016 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 | |||
@@ -15,31 +15,32 @@ | |||
*/ | |||
package com.vaadin.v7.ui; | |||
import java.text.Normalizer.Form; | |||
import java.util.Date; | |||
import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.Component; | |||
import com.vaadin.v7.data.Container; | |||
import com.vaadin.v7.data.Item; | |||
import com.vaadin.v7.data.Property; | |||
/** | |||
* This class contains a basic implementation for {@link TableFieldFactory}. The | |||
* class is singleton, use {@link #get()} method to get reference to the | |||
* instance. | |||
* | |||
* This class contains a basic implementation for both {@link FormFieldFactory} | |||
* and {@link TableFieldFactory}. The class is singleton, use {@link #get()} | |||
* method to get reference to the instance. | |||
* | |||
* <p> | |||
* There are also some static helper methods available for custom built field | |||
* factories. | |||
* | |||
* | |||
*/ | |||
public class DefaultFieldFactory implements TableFieldFactory { | |||
public class DefaultFieldFactory | |||
implements FormFieldFactory, TableFieldFactory { | |||
private static final DefaultFieldFactory instance = new DefaultFieldFactory(); | |||
/** | |||
* Singleton method to get an instance of DefaultFieldFactory. | |||
* | |||
* | |||
* @return an instance of DefaultFieldFactory | |||
*/ | |||
public static DefaultFieldFactory get() { | |||
@@ -49,6 +50,15 @@ public class DefaultFieldFactory implements TableFieldFactory { | |||
protected DefaultFieldFactory() { | |||
} | |||
@Override | |||
public Field<?> createField(Item item, Object propertyId, | |||
Component uiContext) { | |||
Class<?> type = item.getItemProperty(propertyId).getType(); | |||
Field<?> field = createFieldByPropertyType(type); | |||
field.setCaption(createCaptionByPropertyId(propertyId)); | |||
return field; | |||
} | |||
@Override | |||
public Field createField(Container container, Object itemId, | |||
Object propertyId, Component uiContext) { | |||
@@ -63,7 +73,7 @@ public class DefaultFieldFactory implements TableFieldFactory { | |||
/** | |||
* If name follows method naming conventions, convert the name to spaced | |||
* upper case text. For example, convert "firstName" to "First Name" | |||
* | |||
* | |||
* @param propertyId | |||
* @return the formatted caption string | |||
*/ | |||
@@ -74,18 +84,18 @@ public class DefaultFieldFactory implements TableFieldFactory { | |||
/** | |||
* Creates fields based on the property type. | |||
* <p> | |||
* The default field type is {@link TextField}. Other field types generated | |||
* by this method: | |||
* The default field type is {@link LegacyTextField}. Other field types | |||
* generated by this method: | |||
* <p> | |||
* <b>Boolean</b>: {@link CheckBox}.<br/> | |||
* <b>Date</b>: {@link DateField}(resolution: day).<br/> | |||
* <b>Date</b>: {@link LegacyDateField}(resolution: day).<br/> | |||
* <b>Item</b>: {@link Form}. <br/> | |||
* <b>default field type</b>: {@link TextField}. | |||
* <b>default field type</b>: {@link LegacyTextField}. | |||
* <p> | |||
* | |||
* | |||
* @param type | |||
* the type of the property | |||
* @return the most suitable generic {@link Field} for given type | |||
* @return the most suitable generic {@link LegacyField} for given type | |||
*/ | |||
public static Field<?> createFieldByPropertyType(Class<?> type) { | |||
// Null typed properties can not be edited | |||
@@ -93,6 +103,11 @@ public class DefaultFieldFactory implements TableFieldFactory { | |||
return null; | |||
} | |||
// Item field | |||
if (com.vaadin.v7.data.Item.class.isAssignableFrom(type)) { | |||
return new Form(); | |||
} | |||
// Date field | |||
if (Date.class.isAssignableFrom(type)) { | |||
final DateField df = new DateField(); |
@@ -0,0 +1,56 @@ | |||
/* | |||
* Copyright 2000-2016 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.v7.ui; | |||
import java.io.Serializable; | |||
import com.vaadin.ui.Component; | |||
import com.vaadin.v7.data.Item; | |||
import com.vaadin.v7.data.fieldgroup.FieldGroup; | |||
/** | |||
* Factory interface for creating new Field-instances based on {@link Item}, | |||
* property id and uiContext (the component responsible for displaying fields). | |||
* Currently this interface is used by {@link Form}, but might later be used by | |||
* some other components for {@link Field} generation. | |||
* | |||
* <p> | |||
* | |||
* @author Vaadin Ltd. | |||
* @since 6.0 | |||
* @see TableFieldFactory | |||
* @deprecated As of 7.0, use {@link FieldGroup} instead of {@link Form} for | |||
* more flexibility. | |||
*/ | |||
@Deprecated | |||
public interface FormFieldFactory extends Serializable { | |||
/** | |||
* Creates a field based on the item, property id and the component (most | |||
* commonly {@link Form}) where the Field will be presented. | |||
* | |||
* @param item | |||
* the item where the property belongs to. | |||
* @param propertyId | |||
* the Id of the property. | |||
* @param uiContext | |||
* the component where the field is presented, most commonly this | |||
* is {@link Form}. uiContext will not necessary be the parent | |||
* component of the field, but the one that is responsible for | |||
* creating it. | |||
* @return the field suitable for editing the specified data. | |||
*/ | |||
Field<?> createField(Item item, Object propertyId, Component uiContext); | |||
} |
@@ -17,6 +17,7 @@ import com.vaadin.v7.data.Property; | |||
import com.vaadin.v7.data.util.IndexedContainer; | |||
import com.vaadin.v7.data.util.MethodProperty; | |||
import com.vaadin.v7.data.validator.RegexpValidator; | |||
import com.vaadin.v7.ui.Form; | |||
public class SerializationTest { | |||
@@ -28,6 +29,19 @@ public class SerializationTest { | |||
validator2.validate("aaa"); | |||
} | |||
@Test | |||
public void testForm() throws Exception { | |||
Form f = new Form(); | |||
String propertyId = "My property"; | |||
f.addItemProperty(propertyId, | |||
new MethodProperty<>(new Data(), "dummyGetterAndSetter")); | |||
f.replaceWithSelect(propertyId, new Object[] { "a", "b", null }, | |||
new String[] { "Item a", "ITem b", "Null item" }); | |||
serializeAndDeserialize(f); | |||
} | |||
@Test | |||
public void testIndedexContainerItemIds() throws Exception { | |||
IndexedContainer ic = new IndexedContainer(); | |||
@@ -43,22 +57,20 @@ public class SerializationTest { | |||
@Test | |||
public void testMethodPropertyGetter() throws Exception { | |||
MethodProperty<?> mp = new MethodProperty<Object>(new Data(), | |||
"dummyGetter"); | |||
MethodProperty<?> mp = new MethodProperty<>(new Data(), "dummyGetter"); | |||
serializeAndDeserialize(mp); | |||
} | |||
@Test | |||
public void testMethodPropertyGetterAndSetter() throws Exception { | |||
MethodProperty<?> mp = new MethodProperty<Object>(new Data(), | |||
MethodProperty<?> mp = new MethodProperty<>(new Data(), | |||
"dummyGetterAndSetter"); | |||
serializeAndDeserialize(mp); | |||
} | |||
@Test | |||
public void testMethodPropertyInt() throws Exception { | |||
MethodProperty<?> mp = new MethodProperty<Object>(new Data(), | |||
"dummyInt"); | |||
MethodProperty<?> mp = new MethodProperty<>(new Data(), "dummyInt"); | |||
serializeAndDeserialize(mp); | |||
} | |||
@@ -0,0 +1,68 @@ | |||
/* | |||
* 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.v7.tests.server.component.form; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import com.vaadin.v7.ui.Form; | |||
import com.vaadin.v7.ui.TextField; | |||
/** | |||
* Test for {@link Form}. | |||
* | |||
* @author Vaadin Ltd | |||
*/ | |||
public class FormTest { | |||
@Test | |||
public void testFocus() { | |||
Form form = new Form(); | |||
final boolean firstFieldIsFocused[] = new boolean[1]; | |||
TextField field1 = new TextField() { | |||
@Override | |||
public boolean isConnectorEnabled() { | |||
return false; | |||
} | |||
@Override | |||
public void focus() { | |||
firstFieldIsFocused[0] = true; | |||
} | |||
}; | |||
final boolean secondFieldIsFocused[] = new boolean[1]; | |||
TextField field2 = new TextField() { | |||
@Override | |||
public boolean isConnectorEnabled() { | |||
return true; | |||
} | |||
@Override | |||
public void focus() { | |||
secondFieldIsFocused[0] = true; | |||
} | |||
}; | |||
form.addField("a", field1); | |||
form.addField("b", field2); | |||
form.focus(); | |||
Assert.assertTrue("Field with enabled connector is not focused", | |||
secondFieldIsFocused[0]); | |||
Assert.assertFalse("Field with disabled connector is focused", | |||
firstFieldIsFocused[0]); | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
/* | |||
* Copyright 2000-2016 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.v7.shared.form; | |||
import com.vaadin.shared.Connector; | |||
import com.vaadin.v7.shared.AbstractFieldState; | |||
public class FormState extends AbstractFieldState { | |||
{ | |||
primaryStyleName = "v-form"; | |||
} | |||
public Connector layout; | |||
public Connector footer; | |||
} |
@@ -36,6 +36,7 @@ import com.vaadin.ui.ComponentContainer; | |||
import com.vaadin.ui.CustomComponent; | |||
import com.vaadin.ui.GridLayout; | |||
import com.vaadin.ui.GridLayout.Area; | |||
import com.vaadin.ui.HasComponents; | |||
import com.vaadin.ui.Panel; | |||
import com.vaadin.ui.TabSheet; | |||
import com.vaadin.ui.UI; | |||
@@ -89,11 +90,39 @@ public class ComponentSizeValidator implements Serializable { | |||
errors = validateComponentRelativeSizes(it.next(), errors, | |||
parent); | |||
} | |||
} else if (isForm(component)) { | |||
HasComponents form = (HasComponents) component; | |||
for (Iterator<Component> iterator = form.iterator(); iterator | |||
.hasNext();) { | |||
Component child = iterator.next(); | |||
errors = validateComponentRelativeSizes(child, errors, parent); | |||
} | |||
} | |||
return errors; | |||
} | |||
/** | |||
* Comparability form component which is defined in the different jar. | |||
* | |||
* TODO : Normally this logic shouldn't be here. But it means that the whole | |||
* this class has wrong design and impementation and should be refactored. | |||
*/ | |||
private static boolean isForm(Component component) { | |||
if (!(component instanceof HasComponents)) { | |||
return false; | |||
} | |||
Class<?> clazz = component.getClass(); | |||
while (clazz != null) { | |||
if (component.getClass().getName() | |||
.equals("com.vaadin.v7.ui.Form")) { | |||
return true; | |||
} | |||
clazz = clazz.getSuperclass(); | |||
} | |||
return false; | |||
} | |||
private static void printServerError(String msg, | |||
Stack<ComponentInfo> attributes, boolean widthError, | |||
PrintStream errorStream) { | |||
@@ -448,6 +477,12 @@ public class ComponentSizeValidator implements Serializable { | |||
// Other components define row height | |||
return true; | |||
} | |||
} else if (isForm(parent)) { | |||
/* | |||
* If some other part of the form is not relative it determines | |||
* the component width | |||
*/ | |||
return formHasNonRelativeWidthComponent(parent); | |||
} | |||
if (parent instanceof Panel || parent instanceof AbstractSplitPanel | |||
@@ -477,6 +512,24 @@ public class ComponentSizeValidator implements Serializable { | |||
} | |||
} | |||
/** | |||
* Comparability form component which is defined in the different jar. | |||
* | |||
* TODO : Normally this logic shouldn't be here. But it means that the whole | |||
* this class has wrong design and impementation and should be refactored. | |||
*/ | |||
private static boolean formHasNonRelativeWidthComponent(Component form) { | |||
HasComponents parent = (HasComponents) form; | |||
for (Iterator<Component> iterator = parent.iterator(); iterator | |||
.hasNext();) { | |||
if (!hasRelativeWidth(iterator.next())) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
private static boolean hasRelativeHeight(Component component) { | |||
return (component.getHeightUnits() == Unit.PERCENTAGE | |||
&& component.getHeight() > 0); |
@@ -0,0 +1,58 @@ | |||
/* | |||
* Copyright 2012 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.v7.tests.components.form; | |||
import java.util.Arrays; | |||
import com.vaadin.server.UserError; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.tests.data.bean.Person; | |||
import com.vaadin.tests.data.bean.Sex; | |||
import com.vaadin.v7.data.util.BeanItem; | |||
import com.vaadin.v7.ui.Form; | |||
import com.vaadin.v7.ui.TextField; | |||
public class FormTooltips extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
final Form form = new Form(); | |||
form.setId("tooltipForm"); | |||
form.setDescription("Some description"); | |||
form.setItemDataSource( | |||
new BeanItem<>( | |||
new Person("foo", "bar", "baz", 12, Sex.MALE, null)), | |||
Arrays.asList(new String[] { "firstName", "lastName", "age" })); | |||
((TextField) form.getField("firstName")) | |||
.setDescription("Fields own tooltip"); | |||
form.setComponentError(new UserError("Form error")); | |||
addComponent(form); | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "The 'first name' should show its own tooltip, the other fields should show no tooltip"; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 9173; | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
package com.vaadin.v7.tests.components.window; | |||
import com.vaadin.tests.components.TestBase; | |||
import com.vaadin.ui.VerticalLayout; | |||
import com.vaadin.ui.Window; | |||
import com.vaadin.v7.data.Validator; | |||
import com.vaadin.v7.ui.Form; | |||
import com.vaadin.v7.ui.TextField; | |||
public class UndefinedHeightSubWindowAndContent extends TestBase { | |||
@Override | |||
protected void setup() { | |||
Window subWindow = new Window("No scrollbars!"); | |||
subWindow.setWidth("300px"); | |||
subWindow.center(); | |||
subWindow.setModal(true); | |||
VerticalLayout layout = new VerticalLayout(); | |||
layout.setWidth("100%"); | |||
subWindow.setContent(layout); | |||
final Form form = new Form(); | |||
form.setFooter(null); | |||
form.setImmediate(true); | |||
form.setValidationVisible(true); | |||
form.setCaption("This is a form"); | |||
form.setDescription("How do you do?"); | |||
final TextField field1 = new TextField("Write here"); | |||
field1.setImmediate(true); | |||
field1.addValidator(new Validator() { | |||
@Override | |||
public void validate(Object value) throws InvalidValueException { | |||
if (!isValid(value)) { | |||
throw new InvalidValueException("FAIL!"); | |||
} | |||
} | |||
public boolean isValid(Object value) { | |||
return field1.getValue().equals("valid"); | |||
} | |||
}); | |||
form.addField("Field 1", field1); | |||
layout.addComponent(form); | |||
getMainWindow().addWindow(subWindow); | |||
subWindow.bringToFront(); | |||
} | |||
@Override | |||
protected String getDescription() { | |||
return "When both window and its content have undefined height, window must not reserve space for a scroll bar when it is not needed."; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 8852; | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* Copyright 2000-2013 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.v7.tests.components.form; | |||
import org.junit.Test; | |||
import org.openqa.selenium.WebElement; | |||
import com.vaadin.testbench.By; | |||
import com.vaadin.testbench.elements.FormElement; | |||
import com.vaadin.testbench.elements.TextFieldElement; | |||
import com.vaadin.tests.tb3.TooltipTest; | |||
public class FormTooltipsTest extends TooltipTest { | |||
@Test | |||
public void testTooltipConfiguration() throws Exception { | |||
openTestURL(); | |||
// first name tooltip | |||
WebElement fieldElement = $(FormElement.class).first() | |||
.$(TextFieldElement.class).first(); | |||
checkTooltip(fieldElement, "Fields own tooltip"); | |||
clearTooltip(); | |||
checkTooltipNotPresent(); | |||
// first name caption tooltip | |||
checkTooltip($(FormElement.class).first() | |||
.findElement(By.className("v-caption")), "Fields own tooltip"); | |||
clearTooltip(); | |||
checkTooltipNotPresent(); | |||
// Form should not have a description tooltip | |||
checkTooltip($(FormElement.class).first(), null); | |||
// Form error message should not have a tooltip | |||
checkTooltip(By.className("v-form-errormessage"), null); | |||
// last name should have no tooltip | |||
checkTooltip($(TextFieldElement.class).get(1), null); | |||
// last name caption should have no tooltip | |||
checkTooltip($(FormElement.class).first() | |||
.findElements(By.className("v-caption")).get(1), null); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
package com.vaadin.v7.tests.components.window; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import org.openqa.selenium.Keys; | |||
import com.vaadin.testbench.customelements.WindowElement; | |||
import com.vaadin.testbench.elements.TextFieldElement; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
public class UndefinedHeightSubWindowAndContentTest extends MultiBrowserTest { | |||
@Test | |||
public void testUndefinedHeight() { | |||
openTestURL(); | |||
TextFieldElement textField = $(TextFieldElement.class).first(); | |||
textField.click(); | |||
textField.sendKeys("invalid", Keys.ENTER); | |||
WindowElement window = $(WindowElement.class).first(); | |||
int height = window.getSize().getHeight(); | |||
Assert.assertTrue("Window height with validation failure", | |||
161 <= height && height <= 164); | |||
textField.setValue("valid"); | |||
textField.sendKeys(Keys.ENTER); | |||
height = window.getSize().getHeight(); | |||
Assert.assertTrue("Window height with validation success", | |||
136 <= height && height <= 139); | |||
} | |||
} |