/*
* 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.ui;
import java.io.Serializable;
import java.util.Iterator;
import com.vaadin.data.HasValue;
import com.vaadin.shared.ui.customfield.CustomFieldState;
/**
* A {@link HasValue} 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 #doSetValue(Object)} and {@link #getValue()} when necessary.
*
* @param
* field value type
*
* @since 8.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();
}
@Override
protected CustomFieldState getState() {
return (CustomFieldState) super.getState();
}
@Override
protected CustomFieldState getState(boolean markAsDirty) {
return (CustomFieldState) super.getState(markAsDirty);
}
// 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();
}
}