mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-02 19:27:57 +08:00
PL-9948 Pluggable Field factories for FieldGroup / DataGrid / Table
This commit is contained in:
parent
095c87246a
commit
2c46876b81
@ -23,13 +23,18 @@ import com.haulmont.cuba.gui.ComponentPalette;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@org.springframework.stereotype.Component(ComponentsFactory.NAME)
|
||||
public class DesktopComponentsFactory implements ComponentsFactory {
|
||||
|
||||
@Inject
|
||||
protected List<ComponentGenerationStrategy> componentGenerationStrategies;
|
||||
|
||||
private static Map<String, Class<? extends Component>> classes = new HashMap<>();
|
||||
|
||||
private static Map<Class, String> names = new ConcurrentHashMap<>();
|
||||
@ -139,8 +144,27 @@ public class DesktopComponentsFactory implements ComponentsFactory {
|
||||
return type.cast(createComponent(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component createComponent(ComponentGenerationContext context) {
|
||||
List<ComponentGenerationStrategy> strategies = getComponentGenerationStrategies();
|
||||
|
||||
for (ComponentGenerationStrategy strategy : strategies) {
|
||||
Component component = strategy.createComponent(context);
|
||||
if (component != null) {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Can't create component for the '%s' with " +
|
||||
"given meta class '%s'", context.getProperty(), context.getMetaClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer createTimer() {
|
||||
return new DesktopTimer();
|
||||
}
|
||||
|
||||
protected List<ComponentGenerationStrategy> getComponentGenerationStrategies() {
|
||||
return componentGenerationStrategies;
|
||||
}
|
||||
}
|
@ -21,12 +21,16 @@ import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.desktop.gui.DesktopComponentsFactory;
|
||||
import com.haulmont.cuba.desktop.gui.components.DesktopFieldGroup;
|
||||
import com.haulmont.cuba.desktop.gui.executors.impl.DesktopBackgroundWorker;
|
||||
import com.haulmont.cuba.gui.components.ComponentGenerationStrategy;
|
||||
import com.haulmont.cuba.gui.components.DefaultComponentGenerationStrategy;
|
||||
import com.haulmont.cuba.gui.components.FieldGroup;
|
||||
import com.haulmont.cuba.gui.components.FieldGroupTest;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import mockit.Mocked;
|
||||
import mockit.NonStrictExpectations;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DesktopFieldGroupTest extends FieldGroupTest {
|
||||
@ -47,7 +51,14 @@ public class DesktopFieldGroupTest extends FieldGroupTest {
|
||||
|
||||
@Override
|
||||
protected ComponentsFactory createComponentsFactory() {
|
||||
return new DesktopComponentsFactory();
|
||||
return new DesktopComponentsFactory() {
|
||||
@Override
|
||||
public List<ComponentGenerationStrategy> getComponentGenerationStrategies() {
|
||||
DefaultComponentGenerationStrategy strategy = new DefaultComponentGenerationStrategy(messages);
|
||||
strategy.setComponentsFactory(this);
|
||||
return Collections.singletonList(strategy);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.FileDescriptor;
|
||||
import com.haulmont.cuba.core.entity.annotation.CurrencyValue;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Time;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class AbstractComponentGenerationStrategy implements ComponentGenerationStrategy {
|
||||
|
||||
protected Messages messages;
|
||||
protected ComponentsFactory componentsFactory;
|
||||
|
||||
public AbstractComponentGenerationStrategy(Messages messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
protected Component createComponentInternal(ComponentGenerationContext context) {
|
||||
MetaClass metaClass = context.getMetaClass();
|
||||
MetaPropertyPath mpp = resolveMetaPropertyPath(metaClass, context.getProperty());
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
|
||||
if (mpp != null) {
|
||||
Range mppRange = mpp.getRange();
|
||||
if (mppRange.isDatatype()) {
|
||||
Class type = mppRange.asDatatype().getJavaClass();
|
||||
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(metaProperty)) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(metaProperty);
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.ENUMERATION) {
|
||||
return createEnumField(context);
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlDescriptor != null
|
||||
&& "true".equalsIgnoreCase(xmlDescriptor.attributeValue("link"))) {
|
||||
return createDatatypeLinkField(context);
|
||||
} else {
|
||||
boolean hasMaskAttribute = xmlDescriptor != null
|
||||
&& xmlDescriptor.attribute("mask") != null;
|
||||
|
||||
if (type.equals(String.class)) {
|
||||
if (hasMaskAttribute) {
|
||||
return createMaskedField(context);
|
||||
} else {
|
||||
return createStringField(context, mpp);
|
||||
}
|
||||
} else if (type.equals(UUID.class)) {
|
||||
return createUuidField(context);
|
||||
} else if (type.equals(Boolean.class)) {
|
||||
return createBooleanField(context);
|
||||
} else if (type.equals(java.sql.Date.class) || type.equals(Date.class)) {
|
||||
return createDateField(context);
|
||||
} else if (type.equals(Time.class)) {
|
||||
return createTimeField(context);
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
if (hasMaskAttribute) {
|
||||
return createMaskedField(context);
|
||||
} else {
|
||||
Field currencyField = createCurrencyField(context, mpp);
|
||||
if (currencyField != null) {
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
return createNumberField(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mppRange.isClass()) {
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
Class<?> javaType = metaProperty.getJavaType();
|
||||
|
||||
if (FileDescriptor.class.isAssignableFrom(javaType)) {
|
||||
return createFileUploadField(context);
|
||||
}
|
||||
|
||||
if (!Collection.class.isAssignableFrom(javaType)) {
|
||||
return createEntityField(context, mpp);
|
||||
}
|
||||
} else if (mppRange.isEnum()) {
|
||||
return createEnumField(context);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Component createDatatypeLinkField(ComponentGenerationContext context) {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
setDatasource(linkField, context);
|
||||
setLinkFieldAttributes(linkField, context);
|
||||
|
||||
return linkField;
|
||||
}
|
||||
|
||||
protected Field createEnumField(ComponentGenerationContext context) {
|
||||
LookupField component = componentsFactory.createComponent(LookupField.class);
|
||||
setDatasource(component, context);
|
||||
return component;
|
||||
}
|
||||
|
||||
protected Component createMaskedField(ComponentGenerationContext context) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
setDatasource(maskedField, context);
|
||||
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
if (xmlDescriptor != null) {
|
||||
maskedField.setMask(xmlDescriptor.attributeValue("mask"));
|
||||
|
||||
String valueModeStr = xmlDescriptor.attributeValue("valueMode");
|
||||
if (StringUtils.isNotEmpty(valueModeStr)) {
|
||||
maskedField.setValueMode(MaskedField.ValueMode.valueOf(valueModeStr.toUpperCase()));
|
||||
}
|
||||
}
|
||||
maskedField.setValueMode(MaskedField.ValueMode.MASKED);
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
|
||||
return maskedField;
|
||||
}
|
||||
|
||||
protected Component createStringField(ComponentGenerationContext context, MetaPropertyPath mpp) {
|
||||
TextInputField textField = null;
|
||||
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
if (xmlDescriptor != null) {
|
||||
final String rows = xmlDescriptor.attributeValue("rows");
|
||||
if (!StringUtils.isEmpty(rows)) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(Integer.parseInt(rows));
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(context.getProperty()) && mpp != null) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(mpp.getMetaProperty());
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.STRING
|
||||
&& categoryAttribute.getRowsCount() != null && categoryAttribute.getRowsCount() > 1) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(categoryAttribute.getRowsCount());
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
|
||||
if (textField == null) {
|
||||
textField = componentsFactory.createComponent(TextField.class);
|
||||
}
|
||||
|
||||
setDatasource(textField, context);
|
||||
|
||||
String maxLength = xmlDescriptor != null ? xmlDescriptor.attributeValue("maxLength") : null;
|
||||
if (StringUtils.isNotEmpty(maxLength)) {
|
||||
((TextInputField.MaxLengthLimited) textField).setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
protected Field createUuidField(ComponentGenerationContext context) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
setDatasource(maskedField, context);
|
||||
maskedField.setMask("hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh");
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return maskedField;
|
||||
}
|
||||
|
||||
protected Field createBooleanField(ComponentGenerationContext context) {
|
||||
CheckBox component = componentsFactory.createComponent(CheckBox.class);
|
||||
setDatasource(component, context);
|
||||
return component;
|
||||
}
|
||||
|
||||
protected Component createDateField(ComponentGenerationContext context) {
|
||||
DateField dateField = componentsFactory.createComponent(DateField.class);
|
||||
setDatasource(dateField, context);
|
||||
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
final String resolution = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("resolution");
|
||||
String dateFormat = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("dateFormat");
|
||||
|
||||
DateField.Resolution dateResolution = DateField.Resolution.MIN;
|
||||
|
||||
if (StringUtils.isNotEmpty(resolution)) {
|
||||
dateResolution = DateField.Resolution.valueOf(resolution);
|
||||
dateField.setResolution(dateResolution);
|
||||
}
|
||||
|
||||
if (dateFormat == null) {
|
||||
if (dateResolution == DateField.Resolution.DAY) {
|
||||
dateFormat = "msg://dateFormat";
|
||||
} else if (dateResolution == DateField.Resolution.MIN) {
|
||||
dateFormat = "msg://dateTimeFormat";
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(dateFormat)) {
|
||||
if (dateFormat.startsWith("msg://")) {
|
||||
dateFormat = messages.getMainMessage(dateFormat.substring(6, dateFormat.length()));
|
||||
}
|
||||
dateField.setDateFormat(dateFormat);
|
||||
}
|
||||
|
||||
return dateField;
|
||||
}
|
||||
|
||||
protected Component createTimeField(ComponentGenerationContext context) {
|
||||
TimeField timeField = componentsFactory.createComponent(TimeField.class);
|
||||
setDatasource(timeField, context);
|
||||
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
if (xmlDescriptor != null) {
|
||||
String showSeconds = xmlDescriptor.attributeValue("showSeconds");
|
||||
if (Boolean.parseBoolean(showSeconds)) {
|
||||
timeField.setShowSeconds(true);
|
||||
}
|
||||
}
|
||||
|
||||
return timeField;
|
||||
}
|
||||
|
||||
protected Field createNumberField(ComponentGenerationContext context) {
|
||||
TextField component = componentsFactory.createComponent(TextField.class);
|
||||
setDatasource(component, context);
|
||||
return component;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Field createCurrencyField(ComponentGenerationContext context, MetaPropertyPath mpp) {
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty()))
|
||||
return null;
|
||||
|
||||
Object currencyAnnotation = mpp.getMetaProperty().getAnnotations().get(CurrencyValue.class.getName());
|
||||
if (currencyAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CurrencyField component = componentsFactory.createComponent(CurrencyField.class);
|
||||
setDatasource(component, context);
|
||||
return component;
|
||||
}
|
||||
|
||||
protected Field createFileUploadField(ComponentGenerationContext context) {
|
||||
FileUploadField fileUploadField = (FileUploadField) componentsFactory.createComponent(FileUploadField.NAME);
|
||||
fileUploadField.setMode(FileUploadField.FileStoragePutMode.IMMEDIATE);
|
||||
|
||||
fileUploadField.setUploadButtonCaption(null);
|
||||
fileUploadField.setUploadButtonDescription(messages.getMainMessage("upload.submit"));
|
||||
fileUploadField.setUploadButtonIcon("icons/upload.png");
|
||||
|
||||
fileUploadField.setClearButtonCaption(null);
|
||||
fileUploadField.setClearButtonDescription(messages.getMainMessage("upload.clear"));
|
||||
fileUploadField.setClearButtonIcon("icons/remove.png");
|
||||
|
||||
fileUploadField.setShowFileName(true);
|
||||
fileUploadField.setShowClearButton(true);
|
||||
|
||||
setDatasource(fileUploadField, context);
|
||||
|
||||
return fileUploadField;
|
||||
}
|
||||
|
||||
protected Component createEntityField(ComponentGenerationContext context, MetaPropertyPath mpp) {
|
||||
String linkAttribute = null;
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
if (xmlDescriptor != null) {
|
||||
linkAttribute = xmlDescriptor.attributeValue("link");
|
||||
}
|
||||
|
||||
if (!Boolean.parseBoolean(linkAttribute)) {
|
||||
CollectionDatasource optionsDatasource = context.getOptionsDatasource();
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
optionsDatasource = dynamicAttributesGuiTools
|
||||
.createOptionsDatasourceForLookup(metaProperty.getRange().asClass(),
|
||||
attribute.getJoinClause(), attribute.getWhereClause());
|
||||
}
|
||||
}
|
||||
|
||||
PickerField pickerField;
|
||||
if (optionsDatasource == null) {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
setDatasource(pickerField, context);
|
||||
|
||||
if (mpp.getMetaProperty().getType() == MetaProperty.Type.ASSOCIATION) {
|
||||
pickerField.addLookupAction();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools =
|
||||
AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty =
|
||||
(DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField,
|
||||
dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
boolean actionsByMetaAnnotations = ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
if (!actionsByMetaAnnotations) {
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
pickerField.addOpenAction();
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
|
||||
setDatasource(lookupPickerField, context);
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
|
||||
ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
}
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
String captionProperty = xmlDescriptor.attributeValue("captionProperty");
|
||||
if (StringUtils.isNotEmpty(captionProperty)) {
|
||||
pickerField.setCaptionMode(CaptionMode.PROPERTY);
|
||||
pickerField.setCaptionProperty(captionProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return pickerField;
|
||||
} else {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
setDatasource(linkField, context);
|
||||
setLinkFieldAttributes(linkField, context);
|
||||
|
||||
return linkField;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setLinkFieldAttributes(EntityLinkField linkField, ComponentGenerationContext context) {
|
||||
Element xmlDescriptor = context.getXmlDescriptor();
|
||||
if (xmlDescriptor != null) {
|
||||
String linkScreen = xmlDescriptor.attributeValue("linkScreen");
|
||||
if (StringUtils.isNotEmpty(linkScreen)) {
|
||||
linkField.setScreen(linkScreen);
|
||||
}
|
||||
|
||||
final String invokeMethodName = xmlDescriptor.attributeValue("linkInvoke");
|
||||
if (StringUtils.isNotEmpty(invokeMethodName)) {
|
||||
linkField.setCustomClickHandler(new InvokeEntityLinkClickHandler(invokeMethodName));
|
||||
}
|
||||
|
||||
String openTypeAttribute = xmlDescriptor.attributeValue("linkScreenOpenType");
|
||||
if (StringUtils.isNotEmpty(openTypeAttribute)) {
|
||||
WindowManager.OpenType openType = WindowManager.OpenType.valueOf(openTypeAttribute);
|
||||
linkField.setScreenOpenType(openType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected MetaPropertyPath resolveMetaPropertyPath(MetaClass metaClass, String property) {
|
||||
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
|
||||
|
||||
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
|
||||
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
|
||||
}
|
||||
|
||||
return mpp;
|
||||
}
|
||||
|
||||
protected void setDatasource(Field field, ComponentGenerationContext context) {
|
||||
if (context.getDatasource() != null && StringUtils.isNotEmpty(context.getProperty())) {
|
||||
field.setDatasource(context.getDatasource(), context.getProperty());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class InvokeEntityLinkClickHandler implements EntityLinkField.EntityLinkClickHandler {
|
||||
protected final String invokeMethodName;
|
||||
|
||||
public InvokeEntityLinkClickHandler(String invokeMethodName) {
|
||||
this.invokeMethodName = invokeMethodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(EntityLinkField field) {
|
||||
Window frame = ComponentsHelper.getWindow(field);
|
||||
if (frame == null) {
|
||||
throw new IllegalStateException("Please specify Frame for EntityLinkField");
|
||||
}
|
||||
|
||||
Object controller = ComponentsHelper.getFrameController(frame);
|
||||
Method method;
|
||||
try {
|
||||
method = controller.getClass().getMethod(invokeMethodName, EntityLinkField.class);
|
||||
try {
|
||||
method.invoke(controller, field);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Can't invoke method with name '%s'",
|
||||
invokeMethodName), e);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
method = controller.getClass().getMethod(invokeMethodName);
|
||||
try {
|
||||
method.invoke(controller);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(String.format("Can't invoke method with name '%s'",
|
||||
invokeMethodName), ex);
|
||||
}
|
||||
} catch (NoSuchMethodException e1) {
|
||||
throw new IllegalStateException(String.format("No suitable methods named '%s' for invoke",
|
||||
invokeMethodName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,38 +17,15 @@
|
||||
|
||||
package com.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.bali.util.Preconditions;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.FileDescriptor;
|
||||
import com.haulmont.cuba.core.entity.annotation.CurrencyValue;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.AppConfig;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.data.RuntimePropsDatasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Time;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.haulmont.cuba.gui.WindowManager.OpenType;
|
||||
import static com.haulmont.cuba.gui.components.EntityLinkField.EntityLinkClickHandler;
|
||||
|
||||
public abstract class AbstractFieldFactory implements FieldFactory {
|
||||
|
||||
@ -56,403 +33,22 @@ public abstract class AbstractFieldFactory implements FieldFactory {
|
||||
|
||||
@Override
|
||||
public Component createField(Datasource datasource, String property, Element xmlDescriptor) {
|
||||
MetaClass metaClass = datasource.getMetaClass();
|
||||
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
|
||||
MetaClass metaClass = resolveMetaClass(datasource);
|
||||
|
||||
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
|
||||
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
|
||||
}
|
||||
ComponentGenerationContext context = new ComponentGenerationContext(metaClass, property)
|
||||
.setDatasource(datasource)
|
||||
.setOptionsDatasource(getOptionsDatasource(datasource, property))
|
||||
.setXmlDescriptor(xmlDescriptor)
|
||||
.setComponentClass(Table.class);
|
||||
|
||||
if (mpp != null) {
|
||||
Range mppRange = mpp.getRange();
|
||||
if (mppRange.isDatatype()) {
|
||||
Class type = mppRange.asDatatype().getJavaClass();
|
||||
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(metaProperty)) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(metaProperty);
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.ENUMERATION) {
|
||||
return createEnumField(datasource, property);
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlDescriptor != null
|
||||
&& "true".equalsIgnoreCase(xmlDescriptor.attributeValue("link"))) {
|
||||
return createDatatypeLinkField(datasource, property, xmlDescriptor);
|
||||
} else if (type.equals(String.class)) {
|
||||
if (xmlDescriptor != null
|
||||
&& xmlDescriptor.attribute("mask") != null) {
|
||||
return createMaskedField(datasource, property, xmlDescriptor);
|
||||
} else {
|
||||
return createStringField(datasource, property, xmlDescriptor);
|
||||
}
|
||||
} else if (type.equals(UUID.class)) {
|
||||
return createUuidField(datasource, property);
|
||||
} else if (type.equals(Boolean.class)) {
|
||||
return createBooleanField(datasource, property);
|
||||
} else if (type.equals(java.sql.Date.class) || type.equals(Date.class)) {
|
||||
return createDateField(datasource, property, mpp, xmlDescriptor);
|
||||
} else if (type.equals(Time.class)) {
|
||||
return createTimeField(datasource, property, xmlDescriptor);
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
if (xmlDescriptor != null
|
||||
&& xmlDescriptor.attribute("mask") != null) {
|
||||
MaskedField maskedField = (MaskedField) createMaskedField(datasource, property, xmlDescriptor);
|
||||
maskedField.setValueMode(MaskedField.ValueMode.MASKED);
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return maskedField;
|
||||
} else {
|
||||
return createNumberField(datasource, property);
|
||||
}
|
||||
}
|
||||
} else if (mppRange.isClass()) {
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
Class<?> javaType = metaProperty.getJavaType();
|
||||
if (FileDescriptor.class.isAssignableFrom(javaType)) {
|
||||
return createFileUploadField(datasource, property);
|
||||
} else if (!Collection.class.isAssignableFrom(javaType)) {
|
||||
return createEntityField(datasource, property, mpp, xmlDescriptor);
|
||||
}
|
||||
} else if (mppRange.isEnum()) {
|
||||
return createEnumField(datasource, property);
|
||||
}
|
||||
}
|
||||
|
||||
String exceptionMessage;
|
||||
if (mpp != null) {
|
||||
String name = mpp.getRange().isDatatype()
|
||||
? mpp.getRange().asDatatype().toString()
|
||||
: mpp.getRange().asClass().getName();
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with data type: %s", property, name);
|
||||
} else {
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with given data type", property);
|
||||
}
|
||||
throw new UnsupportedOperationException(exceptionMessage);
|
||||
return componentsFactory.createComponent(context);
|
||||
}
|
||||
|
||||
protected Component createFileUploadField(Datasource datasource, String property) {
|
||||
UploadField uploadField = (FileUploadField) componentsFactory.createComponent(FileUploadField.NAME);
|
||||
FileUploadField fileUploadField = ((FileUploadField) uploadField);
|
||||
fileUploadField.setMode(FileUploadField.FileStoragePutMode.IMMEDIATE);
|
||||
|
||||
Messages messages = AppBeans.get(Messages.NAME);
|
||||
|
||||
fileUploadField.setUploadButtonCaption(null);
|
||||
fileUploadField.setUploadButtonDescription(messages.getMainMessage("upload.submit"));
|
||||
fileUploadField.setUploadButtonIcon("icons/upload.png");
|
||||
|
||||
fileUploadField.setClearButtonCaption(null);
|
||||
fileUploadField.setClearButtonIcon("icons/remove.png");
|
||||
fileUploadField.setClearButtonDescription(messages.getMainMessage("upload.clear"));
|
||||
|
||||
fileUploadField.setShowFileName(true);
|
||||
fileUploadField.setShowClearButton(true);
|
||||
|
||||
fileUploadField.setDatasource(datasource, property);
|
||||
return uploadField;
|
||||
}
|
||||
|
||||
protected Component createDatatypeLinkField(Datasource datasource, String property, Element xmlDescriptor) {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
linkField.setDatasource(datasource, property);
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
String linkScreen = xmlDescriptor.attributeValue("linkScreen");
|
||||
if (StringUtils.isNotEmpty(linkScreen)) {
|
||||
linkField.setScreen(linkScreen);
|
||||
}
|
||||
|
||||
final String invokeMethodName = xmlDescriptor.attributeValue("linkInvoke");
|
||||
if (StringUtils.isNotEmpty(invokeMethodName)) {
|
||||
linkField.setCustomClickHandler(new InvokeEntityLinkClickHandler(invokeMethodName));
|
||||
}
|
||||
|
||||
String openTypeAttribute = xmlDescriptor.attributeValue("linkScreenOpenType");
|
||||
if (StringUtils.isNotEmpty(openTypeAttribute)) {
|
||||
OpenType openType = OpenType.valueOf(openTypeAttribute);
|
||||
linkField.setScreenOpenType(openType);
|
||||
}
|
||||
}
|
||||
|
||||
return linkField;
|
||||
}
|
||||
|
||||
protected Component createUuidField(Datasource datasource, String property) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
maskedField.setDatasource(datasource, property);
|
||||
maskedField.setMask("hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh");
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return maskedField;
|
||||
}
|
||||
|
||||
protected Component createNumberField(Datasource datasource, String property) {
|
||||
Component currencyField = createCurrencyField(datasource, property);
|
||||
if (currencyField != null) {
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
TextField textField = componentsFactory.createComponent(TextField.class);
|
||||
textField.setDatasource(datasource, property);
|
||||
return textField;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Component createCurrencyField(Datasource datasource, String property) {
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(property))
|
||||
return null;
|
||||
|
||||
MetaPropertyPath mpp = datasource.getMetaClass().getPropertyPath(property);
|
||||
Preconditions.checkNotNullArgument(mpp, "Could not resolve property path '%s' in '%s'",
|
||||
property, datasource.getMetaClass());
|
||||
|
||||
Object currencyAnnotation = mpp.getMetaProperty().getAnnotations().get(CurrencyValue.class.getName());
|
||||
if (currencyAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CurrencyField currencyField = componentsFactory.createComponent(CurrencyField.class);
|
||||
currencyField.setDatasource(datasource, property);
|
||||
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
protected Component createBooleanField(Datasource datasource, String property) {
|
||||
CheckBox checkBox = componentsFactory.createComponent(CheckBox.class);
|
||||
checkBox.setDatasource(datasource, property);
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
protected Component createMaskedField(Datasource datasource, String property, Element xmlDescriptor) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
maskedField.setDatasource(datasource, property);
|
||||
if (xmlDescriptor != null) {
|
||||
maskedField.setMask(xmlDescriptor.attributeValue("mask"));
|
||||
|
||||
String valueModeStr = xmlDescriptor.attributeValue("valueMode");
|
||||
if (StringUtils.isNotEmpty(valueModeStr)) {
|
||||
maskedField.setValueMode(MaskedField.ValueMode.valueOf(valueModeStr.toUpperCase()));
|
||||
}
|
||||
}
|
||||
return maskedField;
|
||||
}
|
||||
|
||||
protected Component createStringField(Datasource datasource, String property, Element xmlDescriptor) {
|
||||
TextInputField textField = null;
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
final String rows = xmlDescriptor.attributeValue("rows");
|
||||
if (!StringUtils.isEmpty(rows)) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(Integer.parseInt(rows));
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(property)) {
|
||||
MetaClass metaClass = datasource instanceof RuntimePropsDatasource ?
|
||||
((RuntimePropsDatasource) datasource).resolveCategorizedEntityClass() : datasource.getMetaClass();
|
||||
MetaPropertyPath mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
|
||||
if (mpp != null) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(mpp.getMetaProperty());
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.STRING
|
||||
&& categoryAttribute.getRowsCount() != null && categoryAttribute.getRowsCount() > 1) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(categoryAttribute.getRowsCount());
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (textField == null) {
|
||||
textField = componentsFactory.createComponent(TextField.class);
|
||||
}
|
||||
|
||||
textField.setDatasource(datasource, property);
|
||||
|
||||
String maxLength = xmlDescriptor != null ? xmlDescriptor.attributeValue("maxLength") : null;
|
||||
if (StringUtils.isNotEmpty(maxLength)) {
|
||||
((TextInputField.MaxLengthLimited) textField).setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
protected Component createDateField(Datasource datasource, String property, MetaPropertyPath mpp,
|
||||
Element xmlDescriptor) {
|
||||
DateField dateField = componentsFactory.createComponent(DateField.class);
|
||||
dateField.setDatasource(datasource, property);
|
||||
|
||||
final String resolution = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("resolution");
|
||||
String dateFormat = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("dateFormat");
|
||||
|
||||
DateField.Resolution dateResolution = DateField.Resolution.MIN;
|
||||
|
||||
if (StringUtils.isNotEmpty(resolution)) {
|
||||
dateResolution = DateField.Resolution.valueOf(resolution);
|
||||
dateField.setResolution(dateResolution);
|
||||
}
|
||||
|
||||
if (dateFormat == null) {
|
||||
if (dateResolution == DateField.Resolution.DAY) {
|
||||
dateFormat = "msg://dateFormat";
|
||||
} else if (dateResolution == DateField.Resolution.MIN) {
|
||||
dateFormat = "msg://dateTimeFormat";
|
||||
}
|
||||
}
|
||||
Messages messages = AppBeans.get(Messages.NAME);
|
||||
|
||||
if (StringUtils.isNotEmpty(dateFormat)) {
|
||||
if (dateFormat.startsWith("msg://")) {
|
||||
dateFormat = messages.getMainMessage(dateFormat.substring(6, dateFormat.length()));
|
||||
}
|
||||
dateField.setDateFormat(dateFormat);
|
||||
}
|
||||
|
||||
return dateField;
|
||||
}
|
||||
|
||||
protected Component createTimeField(Datasource datasource, String property, Element xmlDescriptor) {
|
||||
TimeField timeField = componentsFactory.createComponent(TimeField.class);
|
||||
timeField.setDatasource(datasource, property);
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
String showSeconds = xmlDescriptor.attributeValue("showSeconds");
|
||||
if (Boolean.parseBoolean(showSeconds)) {
|
||||
timeField.setShowSeconds(true);
|
||||
}
|
||||
}
|
||||
return timeField;
|
||||
}
|
||||
|
||||
protected Component createEntityField(Datasource datasource, String property, MetaPropertyPath mpp, Element xmlDescriptor) {
|
||||
String linkAttribute = null;
|
||||
if (xmlDescriptor != null) {
|
||||
linkAttribute = xmlDescriptor.attributeValue("link");
|
||||
}
|
||||
|
||||
if (!Boolean.parseBoolean(linkAttribute)) {
|
||||
CollectionDatasource optionsDatasource = getOptionsDatasource(datasource, property);
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
optionsDatasource = dynamicAttributesGuiTools.createOptionsDatasourceForLookup(metaProperty.getRange().asClass(),
|
||||
attribute.getJoinClause(), attribute.getWhereClause());
|
||||
}
|
||||
}
|
||||
|
||||
PickerField pickerField;
|
||||
if (optionsDatasource == null) {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
pickerField.setDatasource(datasource, property);
|
||||
if (mpp.getMetaProperty().getType() == MetaProperty.Type.ASSOCIATION) {
|
||||
pickerField.addLookupAction();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField, dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
boolean actionsByMetaAnnotations = ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
if (!actionsByMetaAnnotations) {
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
pickerField.addOpenAction();
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
lookupPickerField.setDatasource(datasource, property);
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
|
||||
ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
}
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
String captionProperty = xmlDescriptor.attributeValue("captionProperty");
|
||||
if (StringUtils.isNotEmpty(captionProperty)) {
|
||||
pickerField.setCaptionMode(CaptionMode.PROPERTY);
|
||||
pickerField.setCaptionProperty(captionProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return pickerField;
|
||||
} else {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
linkField.setDatasource(datasource, property);
|
||||
|
||||
if (xmlDescriptor != null) {
|
||||
String linkScreen = xmlDescriptor.attributeValue("linkScreen");
|
||||
if (StringUtils.isNotEmpty(linkScreen)) {
|
||||
linkField.setScreen(linkScreen);
|
||||
}
|
||||
|
||||
final String invokeMethodName = xmlDescriptor.attributeValue("linkInvoke");
|
||||
if (StringUtils.isNotEmpty(invokeMethodName)) {
|
||||
linkField.setCustomClickHandler(new InvokeEntityLinkClickHandler(invokeMethodName));
|
||||
}
|
||||
|
||||
String openTypeAttribute = xmlDescriptor.attributeValue("linkScreenOpenType");
|
||||
if (StringUtils.isNotEmpty(openTypeAttribute)) {
|
||||
OpenType openType = OpenType.valueOf(openTypeAttribute);
|
||||
linkField.setScreenOpenType(openType);
|
||||
}
|
||||
}
|
||||
|
||||
return linkField;
|
||||
}
|
||||
}
|
||||
|
||||
protected Component createEnumField(Datasource datasource, String property) {
|
||||
LookupField lookupField = componentsFactory.createComponent(LookupField.class);
|
||||
lookupField.setDatasource(datasource, property);
|
||||
|
||||
return lookupField;
|
||||
protected MetaClass resolveMetaClass(Datasource datasource) {
|
||||
return datasource instanceof RuntimePropsDatasource ?
|
||||
((RuntimePropsDatasource) datasource).resolveCategorizedEntityClass() : datasource.getMetaClass();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract CollectionDatasource getOptionsDatasource(Datasource datasource, String property);
|
||||
|
||||
protected static class InvokeEntityLinkClickHandler implements EntityLinkClickHandler {
|
||||
protected final String invokeMethodName;
|
||||
|
||||
public InvokeEntityLinkClickHandler(String invokeMethodName) {
|
||||
this.invokeMethodName = invokeMethodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(EntityLinkField field) {
|
||||
Window frame = ComponentsHelper.getWindow(field);
|
||||
if (frame == null) {
|
||||
throw new IllegalStateException("Please specify Frame for EntityLinkField");
|
||||
}
|
||||
|
||||
Object controller = ComponentsHelper.getFrameController(frame);
|
||||
Method method;
|
||||
try {
|
||||
method = controller.getClass().getMethod(invokeMethodName, EntityLinkField.class);
|
||||
try {
|
||||
method.invoke(controller, field);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
try {
|
||||
method = controller.getClass().getMethod(invokeMethodName);
|
||||
try {
|
||||
method.invoke(controller);
|
||||
} catch (Exception e1) {
|
||||
throw new RuntimeException(e1);
|
||||
}
|
||||
} catch (NoSuchMethodException e1) {
|
||||
throw new IllegalStateException(String.format("No suitable methods named %s for invoke", invokeMethodName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A class that stores information that can be used to create
|
||||
* a component by the {@link com.haulmont.cuba.gui.xml.layout.ComponentsFactory}.
|
||||
*/
|
||||
public class ComponentGenerationContext {
|
||||
protected MetaClass metaClass;
|
||||
protected String property;
|
||||
protected Datasource datasource;
|
||||
protected CollectionDatasource optionsDatasource;
|
||||
protected Element xmlDescriptor;
|
||||
protected Class componentClass;
|
||||
|
||||
/**
|
||||
* Creates an instance of MetaContext.
|
||||
*
|
||||
* @param metaClass an instance of {@link MetaClass} for which a component should be created
|
||||
* @param property a property of meta class for which a component should be created
|
||||
*/
|
||||
public ComponentGenerationContext(MetaClass metaClass, String property) {
|
||||
this.metaClass = metaClass;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance of {@link MetaClass} for which a component should be created
|
||||
*/
|
||||
public MetaClass getMetaClass() {
|
||||
return metaClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an instance of {@link MetaClass} for which a component should be created, using fluent API method.
|
||||
*
|
||||
* @param metaClass an instance of {@link MetaClass} for which a component should be created
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setMetaClass(MetaClass metaClass) {
|
||||
this.metaClass = metaClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a property of meta class for which a component should be created
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a property of meta class for which a component should be created, using fluent API method.
|
||||
*
|
||||
* @param property a property of meta class for which a component should be created
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setProperty(String property) {
|
||||
this.property = property;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a datasource that can be used to create the component
|
||||
*/
|
||||
@Nullable
|
||||
public Datasource getDatasource() {
|
||||
return datasource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a datasource that can be used to create the component, using fluent API method.
|
||||
*
|
||||
* @param datasource a datasource that can be used to create the component
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setDatasource(Datasource datasource) {
|
||||
this.datasource = datasource;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a datasource that can be used as optional to create the component
|
||||
*/
|
||||
@Nullable
|
||||
public CollectionDatasource getOptionsDatasource() {
|
||||
return optionsDatasource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a datasource that can be used as optional to create the component, using fluent API method.
|
||||
*
|
||||
* @param optionsDatasource a datasource that can be used as optional to create the component
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setOptionsDatasource(CollectionDatasource optionsDatasource) {
|
||||
this.optionsDatasource = optionsDatasource;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an XML descriptor which contains additional information
|
||||
*/
|
||||
@Nullable
|
||||
public Element getXmlDescriptor() {
|
||||
return xmlDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an XML descriptor which contains additional information, using fluent API method.
|
||||
*
|
||||
* @param xmlDescriptor an XML descriptor which contains additional information
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setXmlDescriptor(Element xmlDescriptor) {
|
||||
this.xmlDescriptor = xmlDescriptor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a component class for which a component should be created
|
||||
*/
|
||||
@Nullable
|
||||
public Class getComponentClass() {
|
||||
return componentClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a component class for which a component should be created, using fluent API method.
|
||||
*
|
||||
* @param componentClass a component class for which a component should be created
|
||||
* @return this object
|
||||
*/
|
||||
public ComponentGenerationContext setComponentClass(Class componentClass) {
|
||||
this.componentClass = componentClass;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface ComponentGenerationStrategy {
|
||||
/**
|
||||
* Defines the highest precedence for {@link org.springframework.core.Ordered} component strategies of the platform.
|
||||
*/
|
||||
int HIGHEST_PLATFORM_PRECEDENCE = 100;
|
||||
|
||||
/**
|
||||
* Defines the lowest precedence for {@link org.springframework.core.Ordered} component strategies of the platform.
|
||||
*/
|
||||
int LOWEST_PLATFORM_PRECEDENCE = 1000;
|
||||
|
||||
/**
|
||||
* Creates a component according to the given {@link ComponentGenerationContext}.
|
||||
*
|
||||
* @param context the {@link ComponentGenerationContext} instance
|
||||
* @return a component according to the given {@link ComponentGenerationContext}
|
||||
*/
|
||||
@Nullable
|
||||
Component createComponent(ComponentGenerationContext context);
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@org.springframework.stereotype.Component(DataGridEditorComponentGenerationStrategy.NAME)
|
||||
public class DataGridEditorComponentGenerationStrategy extends AbstractComponentGenerationStrategy implements Ordered {
|
||||
public static final String NAME = "cuba_DataGridEditorMetaComponentStrategy";
|
||||
|
||||
@Inject
|
||||
public DataGridEditorComponentGenerationStrategy(Messages messages) {
|
||||
super(messages);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setComponentsFactory(ComponentsFactory componentsFactory) {
|
||||
this.componentsFactory = componentsFactory;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Component createComponent(ComponentGenerationContext context) {
|
||||
if (context.getComponentClass() == null
|
||||
|| !DataGrid.class.isAssignableFrom(context.getComponentClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createComponentInternal(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component createStringField(ComponentGenerationContext context, MetaPropertyPath mpp) {
|
||||
TextField component = componentsFactory.createComponent(TextField.class);
|
||||
setDatasource(component, context);
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Field createEntityField(ComponentGenerationContext context, MetaPropertyPath mpp) {
|
||||
CollectionDatasource optionsDatasource = null;
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
optionsDatasource = dynamicAttributesGuiTools.createOptionsDatasourceForLookup(metaProperty.getRange()
|
||||
.asClass(), attribute.getJoinClause(), attribute.getWhereClause());
|
||||
}
|
||||
}
|
||||
|
||||
PickerField pickerField;
|
||||
if (optionsDatasource == null) {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
setDatasource(pickerField, context);
|
||||
pickerField.addLookupAction();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty =
|
||||
(DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField,
|
||||
dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
PickerField.LookupAction lookupAction =
|
||||
(PickerField.LookupAction) pickerField.getActionNN(PickerField.LookupAction.NAME);
|
||||
// Opening lookup screen in another mode will close editor
|
||||
lookupAction.setLookupScreenOpenType(WindowManager.OpenType.DIALOG);
|
||||
// In case of adding special logic for lookup screen opened from DataGrid editor
|
||||
lookupAction.setLookupScreenParams(ParamsMap.of("dataGridEditor", true));
|
||||
boolean actionsByMetaAnnotations = ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
if (!actionsByMetaAnnotations) {
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
setDatasource(lookupPickerField, context);
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
|
||||
ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
}
|
||||
|
||||
return pickerField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return HIGHEST_PLATFORM_PRECEDENCE + 30;
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ public interface DataGridEditorFieldFactory {
|
||||
* @param datasource editing item datasource
|
||||
* @param property editing item property
|
||||
* @return generated component
|
||||
* @throws IllegalStateException if created component doesn't implement the {@link Field} interface
|
||||
*/
|
||||
Field createField(Datasource datasource, String property);
|
||||
}
|
||||
|
@ -16,40 +16,16 @@
|
||||
|
||||
package com.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.bali.util.Preconditions;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.FileDescriptor;
|
||||
import com.haulmont.cuba.core.entity.annotation.CurrencyValue;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.data.RuntimePropsDatasource;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import java.sql.Time;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@org.springframework.stereotype.Component(DataGridEditorFieldFactory.NAME)
|
||||
public class DataGridEditorFieldFactoryImpl implements DataGridEditorFieldFactory {
|
||||
|
||||
@Inject
|
||||
protected Messages messages;
|
||||
|
||||
@Inject
|
||||
protected ComponentsFactory componentsFactory;
|
||||
|
||||
@ -59,196 +35,22 @@ public class DataGridEditorFieldFactoryImpl implements DataGridEditorFieldFactor
|
||||
}
|
||||
|
||||
protected Field createFieldComponent(Datasource datasource, String property) {
|
||||
MetaClass metaClass = datasource.getMetaClass();
|
||||
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
|
||||
MetaClass metaClass = resolveMetaClass(datasource);
|
||||
|
||||
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
|
||||
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
|
||||
ComponentGenerationContext context = new ComponentGenerationContext(metaClass, property)
|
||||
.setDatasource(datasource)
|
||||
.setComponentClass(DataGrid.class);
|
||||
|
||||
Component component = componentsFactory.createComponent(context);
|
||||
if (component instanceof Field) {
|
||||
return (Field) component;
|
||||
}
|
||||
|
||||
if (mpp != null) {
|
||||
Range mppRange = mpp.getRange();
|
||||
if (mppRange.isDatatype()) {
|
||||
Class type = mppRange.asDatatype().getJavaClass();
|
||||
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(metaProperty)) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(metaProperty);
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.ENUMERATION) {
|
||||
return createEnumField(datasource, property);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals(String.class)) {
|
||||
return createStringField(datasource, property);
|
||||
} else if (type.equals(UUID.class)) {
|
||||
return createUuidField(datasource, property);
|
||||
} else if (type.equals(Boolean.class)) {
|
||||
return createBooleanField(datasource, property);
|
||||
} else if (type.equals(java.sql.Date.class) || type.equals(Date.class)) {
|
||||
return createDateField(datasource, property);
|
||||
} else if (type.equals(Time.class)) {
|
||||
return createTimeField(datasource, property);
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
return createNumberField(datasource, property);
|
||||
}
|
||||
} else if (mppRange.isClass()) {
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
Class<?> javaType = metaProperty.getJavaType();
|
||||
if (FileDescriptor.class.isAssignableFrom(javaType)) {
|
||||
return createFileUploadField(datasource, property);
|
||||
}
|
||||
if (!Collection.class.isAssignableFrom(javaType)) {
|
||||
return createEntityField(datasource, property, mpp);
|
||||
}
|
||||
} else if (mppRange.isEnum()) {
|
||||
return createEnumField(datasource, property);
|
||||
}
|
||||
}
|
||||
|
||||
String exceptionMessage;
|
||||
if (mpp != null) {
|
||||
String name = mpp.getRange().isDatatype()
|
||||
? mpp.getRange().asDatatype().toString()
|
||||
: mpp.getRange().asClass().getName();
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with data type: %s", property, name);
|
||||
} else {
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with given data type", property);
|
||||
}
|
||||
throw new UnsupportedOperationException(exceptionMessage);
|
||||
throw new IllegalStateException("Editor field must implement com.haulmont.cuba.gui.components.Field");
|
||||
}
|
||||
|
||||
protected Field createFileUploadField(Datasource datasource, String property) {
|
||||
FileUploadField fileUploadField = (FileUploadField) componentsFactory.createComponent(FileUploadField.NAME);
|
||||
fileUploadField.setMode(FileUploadField.FileStoragePutMode.IMMEDIATE);
|
||||
|
||||
fileUploadField.setUploadButtonCaption(null);
|
||||
fileUploadField.setUploadButtonDescription(messages.getMainMessage("upload.submit"));
|
||||
fileUploadField.setUploadButtonIcon("icons/upload.png");
|
||||
|
||||
fileUploadField.setClearButtonCaption(null);
|
||||
fileUploadField.setClearButtonDescription(messages.getMainMessage("upload.clear"));
|
||||
fileUploadField.setClearButtonIcon("icons/remove.png");
|
||||
|
||||
fileUploadField.setShowFileName(true);
|
||||
fileUploadField.setShowClearButton(true);
|
||||
|
||||
fileUploadField.setDatasource(datasource, property);
|
||||
return fileUploadField;
|
||||
}
|
||||
|
||||
protected Field createUuidField(Datasource datasource, String property) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
maskedField.setDatasource(datasource, property);
|
||||
maskedField.setMask("hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh");
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return maskedField;
|
||||
}
|
||||
|
||||
protected Field createNumberField(Datasource datasource, String property) {
|
||||
Field currencyField = createCurrencyField(datasource, property);
|
||||
if (currencyField != null) {
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
TextField numberField = componentsFactory.createComponent(TextField.class);
|
||||
numberField.setDatasource(datasource, property);
|
||||
return numberField;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Field createCurrencyField(Datasource datasource, String property) {
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(property))
|
||||
return null;
|
||||
|
||||
MetaPropertyPath mpp = datasource.getMetaClass().getPropertyPath(property);
|
||||
Preconditions.checkNotNullArgument(mpp, "Could not resolve property path '%s' in '%s'",
|
||||
property, datasource.getMetaClass());
|
||||
|
||||
Object currencyAnnotation = mpp.getMetaProperty().getAnnotations().get(CurrencyValue.class.getName());
|
||||
if (currencyAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CurrencyField currencyField = componentsFactory.createComponent(CurrencyField.class);
|
||||
currencyField.setDatasource(datasource, property);
|
||||
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
protected Field createBooleanField(Datasource datasource, String property) {
|
||||
CheckBox checkBox = componentsFactory.createComponent(CheckBox.class);
|
||||
checkBox.setDatasource(datasource, property);
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
protected Field createStringField(Datasource datasource, String property) {
|
||||
TextField textField = componentsFactory.createComponent(TextField.class);
|
||||
textField.setDatasource(datasource, property);
|
||||
return textField;
|
||||
}
|
||||
|
||||
protected Field createDateField(Datasource datasource, String property) {
|
||||
DateField dateField = componentsFactory.createComponent(DateField.class);
|
||||
dateField.setDatasource(datasource, property);
|
||||
return dateField;
|
||||
}
|
||||
|
||||
protected Field createTimeField(Datasource datasource, String property) {
|
||||
TimeField timeField = componentsFactory.createComponent(TimeField.class);
|
||||
timeField.setDatasource(datasource, property);
|
||||
return timeField;
|
||||
}
|
||||
|
||||
protected Field createEntityField(Datasource datasource, String property, MetaPropertyPath mpp) {
|
||||
CollectionDatasource optionsDatasource = null;
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
optionsDatasource = dynamicAttributesGuiTools.createOptionsDatasourceForLookup(metaProperty.getRange()
|
||||
.asClass(), attribute.getJoinClause(), attribute.getWhereClause());
|
||||
}
|
||||
}
|
||||
|
||||
PickerField pickerField;
|
||||
if (optionsDatasource == null) {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
pickerField.setDatasource(datasource, property);
|
||||
pickerField.addLookupAction();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField, dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
PickerField.LookupAction lookupAction =
|
||||
(PickerField.LookupAction) pickerField.getActionNN(PickerField.LookupAction.NAME);
|
||||
// Opening lookup screen in another mode will close editor
|
||||
lookupAction.setLookupScreenOpenType(WindowManager.OpenType.DIALOG);
|
||||
// In case of adding special logic for lookup screen opened from DataGrid editor
|
||||
lookupAction.setLookupScreenParams(ParamsMap.of("dataGridEditor", true));
|
||||
boolean actionsByMetaAnnotations = ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
if (!actionsByMetaAnnotations) {
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
lookupPickerField.setDatasource(datasource, property);
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
|
||||
ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
}
|
||||
|
||||
return pickerField;
|
||||
}
|
||||
|
||||
protected Field createEnumField(Datasource datasource, String property) {
|
||||
LookupField lookupField = componentsFactory.createComponent(LookupField.class);
|
||||
lookupField.setDatasource(datasource, property);
|
||||
return lookupField;
|
||||
protected MetaClass resolveMetaClass(Datasource datasource) {
|
||||
return datasource instanceof RuntimePropsDatasource ?
|
||||
((RuntimePropsDatasource) datasource).resolveCategorizedEntityClass() : datasource.getMetaClass();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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.haulmont.cuba.gui.components;
|
||||
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@org.springframework.stereotype.Component(DefaultComponentGenerationStrategy.NAME)
|
||||
public class DefaultComponentGenerationStrategy extends AbstractComponentGenerationStrategy implements Ordered {
|
||||
public static final String NAME = "cuba_DefaultMetaComponentStrategy";
|
||||
|
||||
@Inject
|
||||
public DefaultComponentGenerationStrategy(Messages messages) {
|
||||
super(messages);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setComponentsFactory(ComponentsFactory componentsFactory) {
|
||||
this.componentsFactory = componentsFactory;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Component createComponent(ComponentGenerationContext context) {
|
||||
return createComponentInternal(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return LOWEST_PLATFORM_PRECEDENCE;
|
||||
}
|
||||
}
|
@ -22,5 +22,13 @@ import org.dom4j.Element;
|
||||
|
||||
public interface FieldFactory {
|
||||
|
||||
/**
|
||||
* Creates a component for {@link Table}.
|
||||
*
|
||||
* @param datasource a datasource
|
||||
* @param property a property
|
||||
* @param xmlDescriptor an xml descriptor
|
||||
* @return created component
|
||||
*/
|
||||
Component createField(Datasource datasource, String property, Element xmlDescriptor);
|
||||
}
|
@ -16,41 +16,15 @@
|
||||
|
||||
package com.haulmont.cuba.gui.components;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.haulmont.bali.util.Preconditions;
|
||||
import com.haulmont.chile.core.datatypes.Datatype;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.FileDescriptor;
|
||||
import com.haulmont.cuba.core.entity.annotation.CurrencyValue;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.data.RuntimePropsDatasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import java.sql.Time;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
@org.springframework.stereotype.Component(FieldGroupFieldFactory.NAME)
|
||||
public class FieldGroupFieldFactoryImpl implements FieldGroupFieldFactory {
|
||||
@Inject
|
||||
protected Messages messages;
|
||||
|
||||
@Inject
|
||||
protected ComponentsFactory componentsFactory;
|
||||
@ -61,363 +35,19 @@ public class FieldGroupFieldFactoryImpl implements FieldGroupFieldFactory {
|
||||
}
|
||||
|
||||
protected GeneratedField createFieldComponent(FieldGroup.FieldConfig fc) {
|
||||
Datasource targetDs = fc.getTargetDatasource();
|
||||
MetaClass metaClass = resolveMetaClass(fc.getTargetDatasource());
|
||||
|
||||
MetaClass metaClass = targetDs.getMetaClass();
|
||||
MetaPropertyPath mpp = resolveMetaPropertyPath(metaClass, fc.getProperty());
|
||||
ComponentGenerationContext context = new ComponentGenerationContext(metaClass, fc.getProperty())
|
||||
.setDatasource(fc.getTargetDatasource())
|
||||
.setOptionsDatasource(fc.getOptionsDatasource())
|
||||
.setXmlDescriptor(fc.getXmlDescriptor())
|
||||
.setComponentClass(FieldGroup.class);
|
||||
|
||||
if (mpp != null) {
|
||||
Range mppRange = mpp.getRange();
|
||||
if (mppRange.isDatatype()) {
|
||||
Datatype datatype = mppRange.asDatatype();
|
||||
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(metaProperty)) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(metaProperty);
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.ENUMERATION) {
|
||||
return createEnumField(fc);
|
||||
}
|
||||
}
|
||||
|
||||
if (fc.getXmlDescriptor() != null
|
||||
&& "true".equalsIgnoreCase(fc.getXmlDescriptor().attributeValue("link"))) {
|
||||
return createDatatypeLinkField(fc);
|
||||
} else if (datatype.getJavaClass().equals(String.class)) {
|
||||
if (fc.getXmlDescriptor() != null
|
||||
&& fc.getXmlDescriptor().attribute("mask") != null) {
|
||||
return createMaskedField(fc);
|
||||
} else {
|
||||
return createStringField(fc);
|
||||
}
|
||||
} else if (datatype.getJavaClass().equals(UUID.class)) {
|
||||
return createUuidField(fc);
|
||||
} else if (datatype.getJavaClass().equals(Boolean.class)) {
|
||||
return createBooleanField(fc);
|
||||
} else if ((datatype.getJavaClass().equals(java.sql.Date.class)) || (datatype.getJavaClass().equals(Date.class))) {
|
||||
return createDateField(fc);
|
||||
} else if (datatype.getJavaClass().equals(Time.class)) {
|
||||
return createTimeField(fc);
|
||||
} else if (Number.class.isAssignableFrom(datatype.getJavaClass())) {
|
||||
if (fc.getXmlDescriptor() != null
|
||||
&& fc.getXmlDescriptor().attribute("mask") != null) {
|
||||
GeneratedField generatedField = createMaskedField(fc);
|
||||
MaskedField maskedField = (MaskedField) generatedField.getComponent();
|
||||
maskedField.setValueMode(MaskedField.ValueMode.MASKED);
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return new GeneratedField(maskedField);
|
||||
} else {
|
||||
GeneratedField currencyField = createCurrencyField(fc);
|
||||
if (currencyField != null) {
|
||||
return currencyField;
|
||||
}
|
||||
|
||||
return createNumberField(fc);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mppRange.isClass()) {
|
||||
MetaProperty metaProperty = mpp.getMetaProperty();
|
||||
Class<?> javaType = metaProperty.getJavaType();
|
||||
if (FileDescriptor.class.isAssignableFrom(javaType)) {
|
||||
return createFileUploadField(fc);
|
||||
}
|
||||
|
||||
return createEntityField(fc);
|
||||
} else if (mppRange.isEnum()) {
|
||||
return createEnumField(fc);
|
||||
}
|
||||
}
|
||||
|
||||
String exceptionMessage;
|
||||
if (mpp != null) {
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with data type: %s", fc.getProperty(),
|
||||
mpp.getRange().asDatatype());
|
||||
} else {
|
||||
exceptionMessage = String.format("Can't create field \"%s\" with given data type", fc.getProperty());
|
||||
}
|
||||
throw new UnsupportedOperationException(exceptionMessage);
|
||||
return new GeneratedField(componentsFactory.createComponent(context));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected GeneratedField createCurrencyField(FieldGroup.FieldConfig fc) {
|
||||
String property = fc.getProperty();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(property))
|
||||
return null;
|
||||
|
||||
Datasource datasource = fc.getTargetDatasource();
|
||||
|
||||
MetaPropertyPath mpp = datasource.getMetaClass().getPropertyPath(property);
|
||||
Preconditions.checkNotNullArgument(mpp, "Could not resolve property path '%s' in '%s'",
|
||||
property, datasource.getMetaClass());
|
||||
|
||||
Object currencyAnnotation = mpp.getMetaProperty().getAnnotations().get(CurrencyValue.class.getName());
|
||||
if (currencyAnnotation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CurrencyField currencyField = componentsFactory.createComponent(CurrencyField.class);
|
||||
currencyField.setDatasource(datasource, property);
|
||||
|
||||
return new GeneratedField(currencyField);
|
||||
}
|
||||
|
||||
protected GeneratedField createUuidField(FieldGroup.FieldConfig fc) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
maskedField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
maskedField.setMask("hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh");
|
||||
maskedField.setSendNullRepresentation(false);
|
||||
return new GeneratedField(maskedField);
|
||||
}
|
||||
|
||||
protected GeneratedField createNumberField(FieldGroup.FieldConfig fc) {
|
||||
TextField textField = componentsFactory.createComponent(TextField.class);
|
||||
textField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
return new GeneratedField(textField);
|
||||
}
|
||||
|
||||
protected GeneratedField createBooleanField(FieldGroup.FieldConfig fc) {
|
||||
CheckBox checkBox = componentsFactory.createComponent(CheckBox.class);
|
||||
checkBox.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
return new GeneratedField(checkBox);
|
||||
}
|
||||
|
||||
protected GeneratedField createMaskedField(FieldGroup.FieldConfig fc) {
|
||||
MaskedField maskedField = componentsFactory.createComponent(MaskedField.class);
|
||||
maskedField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
maskedField.setMask(fc.getXmlDescriptor().attributeValue("mask"));
|
||||
|
||||
String valueModeStr = fc.getXmlDescriptor().attributeValue("valueMode");
|
||||
if (StringUtils.isNotEmpty(valueModeStr)) {
|
||||
maskedField.setValueMode(MaskedField.ValueMode.valueOf(valueModeStr.toUpperCase()));
|
||||
}
|
||||
}
|
||||
return new GeneratedField(maskedField);
|
||||
}
|
||||
|
||||
protected GeneratedField createStringField(FieldGroup.FieldConfig fc) {
|
||||
TextInputField textField = null;
|
||||
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
final String rows = fc.getXmlDescriptor().attributeValue("rows");
|
||||
if (!StringUtils.isEmpty(rows)) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(Integer.parseInt(rows));
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(fc.getProperty())) {
|
||||
MetaClass metaClass = fc.getTargetDatasource() instanceof RuntimePropsDatasource ?
|
||||
((RuntimePropsDatasource) fc.getTargetDatasource()).resolveCategorizedEntityClass() : fc.getTargetDatasource().getMetaClass();
|
||||
MetaPropertyPath mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, fc.getProperty());
|
||||
if (mpp != null) {
|
||||
CategoryAttribute categoryAttribute = DynamicAttributesUtils.getCategoryAttribute(mpp.getMetaProperty());
|
||||
if (categoryAttribute != null && categoryAttribute.getDataType() == PropertyType.STRING
|
||||
&& categoryAttribute.getRowsCount() != null && categoryAttribute.getRowsCount() > 1) {
|
||||
TextArea textArea = componentsFactory.createComponent(TextArea.class);
|
||||
textArea.setRows(categoryAttribute.getRowsCount());
|
||||
textField = textArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (textField == null) {
|
||||
textField = componentsFactory.createComponent(TextField.class);
|
||||
}
|
||||
|
||||
textField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
String maxLength = fc.getXmlDescriptor() != null ? fc.getXmlDescriptor().attributeValue("maxLength") : null;
|
||||
if (!Strings.isNullOrEmpty(maxLength)) {
|
||||
((TextInputField.MaxLengthLimited) textField).setMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
|
||||
return new GeneratedField(textField);
|
||||
}
|
||||
|
||||
protected GeneratedField createEnumField(FieldGroup.FieldConfig fc) {
|
||||
LookupField lookupField = componentsFactory.createComponent(LookupField.class);
|
||||
lookupField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
return new GeneratedField(lookupField);
|
||||
}
|
||||
|
||||
protected GeneratedField createDatatypeLinkField(FieldGroup.FieldConfig fc) {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
linkField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
setLinkFieldAttributes(fc, linkField);
|
||||
|
||||
return new GeneratedField(linkField);
|
||||
}
|
||||
|
||||
protected GeneratedField createDateField(FieldGroup.FieldConfig fc) {
|
||||
DateField dateField = componentsFactory.createComponent(DateField.class);
|
||||
dateField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
Element xmlDescriptor = fc.getXmlDescriptor();
|
||||
|
||||
String resolution = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("resolution");
|
||||
String dateFormat = xmlDescriptor == null ? null : xmlDescriptor.attributeValue("dateFormat");
|
||||
|
||||
DateField.Resolution dateResolution = DateField.Resolution.MIN;
|
||||
|
||||
if (StringUtils.isNotEmpty(resolution)) {
|
||||
dateResolution = DateField.Resolution.valueOf(resolution);
|
||||
dateField.setResolution(dateResolution);
|
||||
}
|
||||
|
||||
if (dateFormat == null) {
|
||||
if (dateResolution == DateField.Resolution.DAY) {
|
||||
dateFormat = "msg://dateFormat";
|
||||
} else if (dateResolution == DateField.Resolution.MIN) {
|
||||
dateFormat = "msg://dateTimeFormat";
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(dateFormat)) {
|
||||
if (dateFormat.startsWith("msg://")) {
|
||||
dateFormat = messages.getMainMessage(dateFormat.substring(6, dateFormat.length()));
|
||||
}
|
||||
dateField.setDateFormat(dateFormat);
|
||||
}
|
||||
|
||||
return new GeneratedField(dateField);
|
||||
}
|
||||
|
||||
protected GeneratedField createTimeField(FieldGroup.FieldConfig fc) {
|
||||
TimeField timeField = componentsFactory.createComponent(TimeField.class);
|
||||
timeField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
String showSeconds = fc.getXmlDescriptor().attributeValue("showSeconds");
|
||||
if (Boolean.parseBoolean(showSeconds)) {
|
||||
timeField.setShowSeconds(true);
|
||||
}
|
||||
}
|
||||
return new GeneratedField(timeField);
|
||||
}
|
||||
|
||||
protected GeneratedField createFileUploadField(FieldGroup.FieldConfig fc) {
|
||||
FileUploadField fileUploadField = componentsFactory.createComponent(FileUploadField.class);
|
||||
fileUploadField.setMode(FileUploadField.FileStoragePutMode.IMMEDIATE);
|
||||
|
||||
fileUploadField.setUploadButtonCaption(null);
|
||||
fileUploadField.setUploadButtonDescription(messages.getMainMessage("upload.submit"));
|
||||
fileUploadField.setUploadButtonIcon("icons/upload.png");
|
||||
|
||||
fileUploadField.setClearButtonCaption(null);
|
||||
fileUploadField.setClearButtonIcon("icons/remove.png");
|
||||
fileUploadField.setClearButtonDescription(messages.getMainMessage("upload.clear"));
|
||||
|
||||
fileUploadField.setShowFileName(true);
|
||||
fileUploadField.setShowClearButton(true);
|
||||
|
||||
fileUploadField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
return new GeneratedField(fileUploadField);
|
||||
}
|
||||
|
||||
protected GeneratedField createEntityField(FieldGroup.FieldConfig fc) {
|
||||
MetaClass metaClass = fc.getTargetDatasource().getMetaClass();
|
||||
MetaPropertyPath mpp = resolveMetaPropertyPath(metaClass, fc.getProperty());
|
||||
|
||||
String linkAttribute = null;
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
linkAttribute = fc.getXmlDescriptor().attributeValue("link");
|
||||
}
|
||||
|
||||
if (!Boolean.parseBoolean(linkAttribute)) {
|
||||
CollectionDatasource optionsDatasource = fc.getOptionsDatasource();
|
||||
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
optionsDatasource = dynamicAttributesGuiTools.createOptionsDatasourceForLookup(metaProperty.getRange().asClass(),
|
||||
attribute.getJoinClause(), attribute.getWhereClause());
|
||||
}
|
||||
}
|
||||
|
||||
PickerField pickerField;
|
||||
if (optionsDatasource == null) {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
|
||||
pickerField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
if (mpp.getMetaProperty().getType() == MetaProperty.Type.ASSOCIATION) {
|
||||
pickerField.addLookupAction();
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField, dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
boolean actionsByMetaAnnotations = ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
if (!actionsByMetaAnnotations) {
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
pickerField.addOpenAction();
|
||||
pickerField.addClearAction();
|
||||
}
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
|
||||
lookupPickerField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
|
||||
ComponentsHelper.createActionsByMetaAnnotations(pickerField);
|
||||
}
|
||||
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
String captionProperty = fc.getXmlDescriptor().attributeValue("captionProperty");
|
||||
if (StringUtils.isNotEmpty(captionProperty)) {
|
||||
pickerField.setCaptionMode(CaptionMode.PROPERTY);
|
||||
pickerField.setCaptionProperty(captionProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return new GeneratedField(pickerField);
|
||||
} else {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
||||
linkField.setDatasource(fc.getTargetDatasource(), fc.getProperty());
|
||||
|
||||
setLinkFieldAttributes(fc, linkField);
|
||||
|
||||
return new GeneratedField(linkField);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setLinkFieldAttributes(FieldGroup.FieldConfig fc, EntityLinkField linkField) {
|
||||
if (fc.getXmlDescriptor() != null) {
|
||||
String linkScreen = fc.getXmlDescriptor().attributeValue("linkScreen");
|
||||
if (StringUtils.isNotEmpty(linkScreen)) {
|
||||
linkField.setScreen(linkScreen);
|
||||
}
|
||||
|
||||
final String invokeMethodName = fc.getXmlDescriptor().attributeValue("linkInvoke");
|
||||
if (StringUtils.isNotEmpty(invokeMethodName)) {
|
||||
linkField.setCustomClickHandler(new AbstractFieldFactory.InvokeEntityLinkClickHandler(invokeMethodName));
|
||||
}
|
||||
|
||||
String openTypeAttribute = fc.getXmlDescriptor().attributeValue("linkScreenOpenType");
|
||||
if (StringUtils.isNotEmpty(openTypeAttribute)) {
|
||||
WindowManager.OpenType openType = WindowManager.OpenType.valueOf(openTypeAttribute);
|
||||
linkField.setScreenOpenType(openType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected MetaPropertyPath resolveMetaPropertyPath(MetaClass metaClass, String property) {
|
||||
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
|
||||
|
||||
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
|
||||
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
|
||||
}
|
||||
|
||||
return mpp;
|
||||
protected MetaClass resolveMetaClass(Datasource datasource) {
|
||||
return datasource instanceof RuntimePropsDatasource ?
|
||||
((RuntimePropsDatasource) datasource).resolveCategorizedEntityClass() : datasource.getMetaClass();
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
package com.haulmont.cuba.gui.xml.layout;
|
||||
|
||||
import com.haulmont.cuba.gui.components.Component;
|
||||
import com.haulmont.cuba.gui.components.ComponentGenerationContext;
|
||||
import com.haulmont.cuba.gui.components.ComponentGenerationStrategy;
|
||||
import com.haulmont.cuba.gui.components.Timer;
|
||||
|
||||
/**
|
||||
@ -45,6 +47,21 @@ public interface ComponentsFactory {
|
||||
*/
|
||||
<T extends Component> T createComponent(Class<T> type);
|
||||
|
||||
/**
|
||||
* Creates a component according to the given {@link ComponentGenerationContext}.
|
||||
* <p>
|
||||
* Trying to find {@link ComponentGenerationStrategy} realisations. If at least one strategy exists, then:
|
||||
* <ol>
|
||||
* <li>Iterates over strategies according to the {@link org.springframework.core.Ordered} interface.</li>
|
||||
* <li>The first not {@code null} component will be returned.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param context the {@link ComponentGenerationContext} instance
|
||||
* @return a component instance for the current client type (web or desktop)
|
||||
* @throws IllegalArgumentException if no component can be created for a given context
|
||||
*/
|
||||
Component createComponent(ComponentGenerationContext context);
|
||||
|
||||
/**
|
||||
* Create a timer instance.
|
||||
* @return client-specific implementation of the timer
|
||||
|
@ -55,7 +55,6 @@ public class FieldGroupTest extends CubaClientTestCase {
|
||||
|
||||
fieldFactory = new TestFieldGroupFieldFactoryImpl() {
|
||||
{
|
||||
this.messages = FieldGroupTest.this.messages;
|
||||
this.componentsFactory = FieldGroupTest.this.componentsFactory;
|
||||
}
|
||||
};
|
||||
|
@ -24,12 +24,17 @@ import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import com.haulmont.cuba.web.gui.components.*;
|
||||
import com.haulmont.cuba.web.gui.components.mainwindow.*;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@org.springframework.stereotype.Component(ComponentsFactory.NAME)
|
||||
public class WebComponentsFactory implements ComponentsFactory {
|
||||
|
||||
@Inject
|
||||
protected List<ComponentGenerationStrategy> componentGenerationStrategies;
|
||||
|
||||
private static Map<String, Class<? extends Component>> classes = new ConcurrentHashMap<>();
|
||||
|
||||
private static Map<Class, String> names = new ConcurrentHashMap<>();
|
||||
@ -176,8 +181,27 @@ public class WebComponentsFactory implements ComponentsFactory {
|
||||
return type.cast(createComponent(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component createComponent(ComponentGenerationContext context) {
|
||||
List<ComponentGenerationStrategy> strategies = getComponentGenerationStrategies();
|
||||
|
||||
for (ComponentGenerationStrategy strategy : strategies) {
|
||||
Component component = strategy.createComponent(context);
|
||||
if (component != null) {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Can't create component for the '%s' with " +
|
||||
"given meta class '%s'", context.getProperty(), context.getMetaClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timer createTimer() {
|
||||
return new WebTimer();
|
||||
}
|
||||
|
||||
protected List<ComponentGenerationStrategy> getComponentGenerationStrategies() {
|
||||
return componentGenerationStrategies;
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ package com.haulmont.cuba.web.test.ui;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
import com.haulmont.cuba.gui.components.ComponentGenerationStrategy;
|
||||
import com.haulmont.cuba.gui.components.DefaultComponentGenerationStrategy;
|
||||
import com.haulmont.cuba.gui.components.FieldGroup;
|
||||
import com.haulmont.cuba.gui.components.FieldGroupTest;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
@ -28,6 +30,8 @@ import com.vaadin.ui.GridLayout;
|
||||
import mockit.Mocked;
|
||||
import mockit.NonStrictExpectations;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WebFieldGroupTest extends FieldGroupTest {
|
||||
@ -53,7 +57,14 @@ public class WebFieldGroupTest extends FieldGroupTest {
|
||||
|
||||
@Override
|
||||
protected ComponentsFactory createComponentsFactory() {
|
||||
return new WebComponentsFactory();
|
||||
return new WebComponentsFactory() {
|
||||
@Override
|
||||
public List<ComponentGenerationStrategy> getComponentGenerationStrategies() {
|
||||
DefaultComponentGenerationStrategy strategy = new DefaultComponentGenerationStrategy(messages);
|
||||
strategy.setComponentsFactory(this);
|
||||
return Collections.singletonList(strategy);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user