com.vaadin.ui.CustomField Maven / Gradle / Ivy
/*
* Vaadin Framework 7
*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.ui;
import java.io.Serializable;
import java.util.Iterator;
import com.vaadin.data.Property;
/**
* A {@link Field} whose UI content can be constructed by the user, enabling the
* creation of e.g. form fields by composing Vaadin components. Customization of
* both the visual presentation and the logic of the field is possible.
*
* Subclasses must implement {@link #getType()} and {@link #initContent()}.
*
* Most custom fields can simply compose a user interface that calls the methods
* {@link #setInternalValue(Object)} and {@link #getInternalValue()} when
* necessary.
*
* It is also possible to override {@link #validate()},
* {@link #setInternalValue(Object)}, {@link #commit()},
* {@link #setPropertyDataSource(Property)}, {@link #isEmpty()} and other logic
* of the field. Methods overriding {@link #setInternalValue(Object)} should
* also call the corresponding superclass method.
*
* @param
* field value type
*
* @since 7.0
*/
public abstract class CustomField extends AbstractField
implements HasComponents {
/**
* The root component implementing the custom component.
*/
private Component root = null;
/**
* Constructs a new custom field.
*
*
* The component is implemented by wrapping the methods of the composition
* root component given as parameter. The composition root must be set
* before the component can be used.
*
*/
public CustomField() {
// expand horizontally by default
setWidth(100, Unit.PERCENTAGE);
}
/**
* Constructs the content and notifies it that the {@link CustomField} is
* attached to a window.
*
* @see com.vaadin.ui.Component#attach()
*/
@Override
public void attach() {
// First call super attach to notify all children (none if content has
// not yet been created)
super.attach();
// If the content has not yet been created, create and attach it at
// this point by calling getContent()
getContent();
}
/**
* Returns the content (UI) of the custom component.
*
* @return Component
*/
protected Component getContent() {
if (null == root) {
root = initContent();
root.setParent(this);
}
return root;
}
/**
* Create the content component or layout for the field. Subclasses of
* {@link CustomField} should implement this method.
*
* Note that this method is called when the CustomField is attached to a
* layout or when {@link #getContent()} is called explicitly for the first
* time. It is only called once for a {@link CustomField}.
*
* @return {@link Component} representing the UI of the CustomField
*/
protected abstract Component initContent();
// Size related methods
// TODO might not be necessary to override but following the pattern from
// AbstractComponentContainer
@Override
public void setHeight(float height, Unit unit) {
super.setHeight(height, unit);
markAsDirtyRecursive();
}
@Override
public void setWidth(float width, Unit unit) {
super.setWidth(width, unit);
markAsDirtyRecursive();
}
// ComponentContainer methods
private class ComponentIterator
implements Iterator, Serializable {
boolean first = root != null;
@Override
public boolean hasNext() {
return first;
}
@Override
public Component next() {
first = false;
return getContent();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public Iterator iterator() {
return new ComponentIterator();
}
/**
* Sets the component to which all methods from the {@link Focusable}
* interface should be delegated.
*
* 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.
*
* 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);
}
}
}