blob: 5d17f360ac7b9a995adddfc9e1e219d50448c553 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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.google.gwt.editor.rebind.model;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.editor.client.CompositeEditor;
import com.google.gwt.editor.client.HasEditorDelegate;
import com.google.gwt.editor.client.HasEditorErrors;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.editor.client.ValueAwareEditor;
/**
* Describes how an Editor is related to bean properties. This type contains
* answers to questions asked by the generator code.
*/
public class EditorData {
/**
* Used to construct EditorData objects.
*/
public static class Builder {
private EditorAccess access;
private EditorData data = new EditorData();
private final TreeLogger logger;
private EditorData parent;
public Builder(TreeLogger logger) {
this.logger = logger;
}
public Builder access(EditorAccess access) throws UnableToCompleteException {
this.access = access;
data.declaredPath = access.getPath();
data.editorType = access.getEditorType();
data.editedType = EditorModel.calculateEditedType(logger, data.editorType);
data.simpleExpression = access.getExpresson();
TypeOracle oracle = data.editorType.getOracle();
JClassType leafType = oracle.findType(LeafValueEditor.class.getName());
data.isLeaf = leafType.isAssignableFrom(data.editorType);
JClassType composedType = oracle.findType(CompositeEditor.class.getName());
data.isCompositeEditor = composedType.isAssignableFrom(data.editorType);
JClassType hasDelegateType = oracle.findType(HasEditorDelegate.class.getName());
JClassType hasEditorErrorsType = oracle.findType(HasEditorErrors.class.getName());
data.isDelegateRequired = hasDelegateType.isAssignableFrom(data.editorType)
|| hasEditorErrorsType.isAssignableFrom(data.editorType)
|| !ModelUtils.isValueType(oracle, data.editedType);
JClassType valueAwareType = oracle.findType(ValueAwareEditor.class.getName());
data.isValueAware = valueAwareType.isAssignableFrom(data.editorType);
return this;
}
public Builder beanOwnerExpression(String value) {
data.beanOwnerExpression = value;
return this;
}
public Builder beanOwnerGuard(String value) {
data.beanOwnerGuard = value;
return this;
}
public EditorData build() throws UnableToCompleteException {
if (data == null) {
throw new IllegalStateException();
}
try {
data.editorExpression = (parent == null ? ""
: (parent.getExpression() + "."))
+ access.getExpresson();
data.path = (parent == null ? "" : (parent.getPath() + "."))
+ access.getPath();
if (data.isCompositeEditor) {
TreeLogger compositeLogger = logger.branch(TreeLogger.DEBUG,
"Examining composite editor at " + data.path);
JClassType subEditorType = EditorModel.calculateCompositeTypes(data.editorType)[1];
data.composedData = new Builder(compositeLogger).access(
EditorAccess.root(subEditorType)).parent(data).build();
}
return data;
} finally {
data = null;
}
}
public Builder getterName(String value) {
data.getterName = value;
return this;
}
public Builder parent(EditorData value) {
parent = value;
return this;
}
public Builder propertyOwnerType(JClassType ownerType) {
data.propertyOwnerType = ownerType;
return this;
}
public Builder setterName(String value) {
data.setterName = value;
return this;
}
}
private String beanOwnerExpression = "";
private String beanOwnerGuard = "true";
private EditorData composedData;
private String declaredPath;
private JClassType editedType;
private JClassType editorType;
private String editorExpression;
private String getterName;
private boolean isLeaf;
private boolean isCompositeEditor;
private boolean isDelegateRequired;
private boolean isValueAware;
private String path;
private JClassType propertyOwnerType;
private String setterName;
private String simpleExpression;
private EditorData() {
}
public String getBeanOwnerExpression() {
return beanOwnerExpression;
}
public String getBeanOwnerGuard(String ownerExpression) {
return String.format(beanOwnerGuard, ownerExpression);
}
public EditorData getComposedData() {
return composedData;
}
/**
* Gets the path specified by the {@code @Path} annotation or inferred via
* convention.
*/
public String getDeclaredPath() {
return declaredPath;
}
public JClassType getEditedType() {
return editedType;
}
public JClassType getEditorType() {
return editorType;
}
/**
* Returns a complete expression to retrieve the editor.
*/
public String getExpression() {
return editorExpression;
}
public String getGetterName() {
return getterName;
}
/**
* Returns the complete path of the editor, relative to the root object.
*/
public String getPath() {
return path;
}
public String getPropertyName() {
return getPath().substring(getPath().lastIndexOf('.') + 1);
}
/**
* Mainly useful for nested properties where there may not be an editor for
* the enclosing instance (e.g. <code>person.manager.name</code>).
*/
public JClassType getPropertyOwnerType() {
return propertyOwnerType;
}
public String getSetterName() {
return setterName;
}
/**
* Returns an expression relative to the enclosing Editor to retrieve the
* editor.
*/
public String getSimpleExpression() {
return simpleExpression;
}
/**
* Indicates if the Editor is a {@link ComposedEditor .
*/
public boolean isCompositeEditor() {
return isCompositeEditor;
}
/**
* Returns <code>true</code> if the editor "reaches through" an interstitial
* property.
*/
public boolean isDeclaredPathNested() {
return declaredPath.contains(".");
}
/**
* Returns <code>true<code> if the editor requires an EditorDelegate.
*/
public boolean isDelegateRequired() {
return isDelegateRequired;
}
/**
* Indicates if the Editor extends {@link LeafValueEditor}.
*/
public boolean isLeafValueEditor() {
return isLeaf;
}
/**
* Indicates if the Editor extends {@link ValueAwareEditor}.
*/
public boolean isValueAwareEditor() {
return isValueAware;
}
/**
* For debugging use only.
*/
@Override
public String toString() {
return getPath() + " = " + getEditorType();
}
}