mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-04 04:07:42 +08:00
PL-8260 Ability to set up filtering conditions for dynamic attributes values with Entity type
This commit is contained in:
parent
692178f0ac
commit
ec55904074
@ -718,6 +718,8 @@ create table SYS_CATEGORY_ATTR(
|
||||
WIDTH varchar(20),
|
||||
ROWS_COUNT integer,
|
||||
IS_COLLECTION boolean,
|
||||
JOIN_CLAUSE varchar(4000),
|
||||
WHERE_CLAUSE varchar(4000),
|
||||
--
|
||||
primary key (ID)
|
||||
)^
|
||||
|
@ -761,6 +761,8 @@ create table SYS_CATEGORY_ATTR (
|
||||
WIDTH varchar(20),
|
||||
ROWS_COUNT integer,
|
||||
IS_COLLECTION tinyint,
|
||||
JOIN_CLAUSE varchar(4000),
|
||||
WHERE_CLAUSE varchar(4000),
|
||||
--
|
||||
primary key nonclustered (ID),
|
||||
constraint SYS_CATEGORY_ATTR_CATEGORY_ID foreign key (CATEGORY_ID) references SYS_CATEGORY(ID)
|
||||
|
@ -766,6 +766,8 @@ create table SYS_CATEGORY_ATTR (
|
||||
WIDTH varchar(20),
|
||||
ROWS_COUNT integer,
|
||||
IS_COLLECTION boolean,
|
||||
JOIN_CLAUSE varchar(4000),
|
||||
WHERE_CLAUSE varchar(4000),
|
||||
--
|
||||
primary key (ID),
|
||||
constraint SYS_CATEGORY_ATTR_CATEGORY_ID foreign key (CATEGORY_ID) references SYS_CATEGORY(ID)
|
||||
|
@ -81,6 +81,9 @@ create table SYS_CATEGORY_ATTR (
|
||||
WIDTH varchar2(20),
|
||||
ROWS_COUNT integer,
|
||||
IS_COLLECTION char(1),
|
||||
JOIN_CLAUSE varchar2(4000),
|
||||
WHERE_CLAUSE varchar2(4000),
|
||||
|
||||
primary key(ID)
|
||||
)^
|
||||
create index IDX_SYS_CATEGORY_ATTR_CATEGORY on SYS_CATEGORY_ATTR(CATEGORY_ID)^
|
||||
|
@ -730,6 +730,8 @@ create table SYS_CATEGORY_ATTR (
|
||||
WIDTH varchar(20),
|
||||
ROWS_COUNT integer,
|
||||
IS_COLLECTION boolean,
|
||||
JOIN_CLAUSE varchar(4000),
|
||||
WHERE_CLAUSE varchar(4000),
|
||||
--
|
||||
primary key (ID),
|
||||
constraint SYS_CATEGORY_ATTR_CATEGORY_ID foreign key (CATEGORY_ID) references SYS_CATEGORY(ID)
|
||||
|
@ -0,0 +1,2 @@
|
||||
alter table SYS_CATEGORY_ATTR add JOIN_CLAUSE varchar(4000);
|
||||
alter table SYS_CATEGORY_ATTR add WHERE_CLAUSE varchar(4000);
|
@ -0,0 +1,2 @@
|
||||
alter table SYS_CATEGORY_ATTR add JOIN_CLAUSE varchar(4000);
|
||||
alter table SYS_CATEGORY_ATTR add WHERE_CLAUSE varchar(4000);
|
@ -0,0 +1,2 @@
|
||||
alter table SYS_CATEGORY_ATTR add JOIN_CLAUSE varchar(4000);
|
||||
alter table SYS_CATEGORY_ATTR add WHERE_CLAUSE varchar(4000);
|
@ -0,0 +1,2 @@
|
||||
alter table SYS_CATEGORY_ATTR add JOIN_CLAUSE varchar2(4000)^
|
||||
alter table SYS_CATEGORY_ATTR add WHERE_CLAUSE varchar2(4000)^
|
@ -0,0 +1,2 @@
|
||||
alter table SYS_CATEGORY_ATTR add JOIN_CLAUSE varchar(4000);
|
||||
alter table SYS_CATEGORY_ATTR add WHERE_CLAUSE varchar(4000);
|
@ -120,6 +120,26 @@ public class DesktopListEditor extends DesktopAbstractField<JPanel> implements L
|
||||
delegate.setOptionsList(optionsList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityJoinClause() {
|
||||
return delegate.getEntityJoinClause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityJoinClause(String entityJoinClause) {
|
||||
delegate.setEntityJoinClause(entityJoinClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityWhereClause() {
|
||||
return delegate.getEntityWhereClause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityWhereClause(String entityWhereClause) {
|
||||
delegate.setEntityWhereClause(entityWhereClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Datasource getDatasource() {
|
||||
return null;
|
||||
|
@ -109,6 +109,12 @@ public class CategoryAttribute extends StandardEntity {
|
||||
@Column(name = "IS_COLLECTION")
|
||||
private Boolean isCollection = false;
|
||||
|
||||
@Column(name = "WHERE_CLAUSE")
|
||||
private String whereClause;
|
||||
|
||||
@Column(name = "JOIN_CLAUSE")
|
||||
private String joinClause;
|
||||
|
||||
public void setCategory(Category entityType) {
|
||||
this.category = entityType;
|
||||
}
|
||||
@ -300,6 +306,22 @@ public class CategoryAttribute extends StandardEntity {
|
||||
this.isCollection = isCollection;
|
||||
}
|
||||
|
||||
public String getWhereClause() {
|
||||
return whereClause;
|
||||
}
|
||||
|
||||
public void setWhereClause(String whereClause) {
|
||||
this.whereClause = whereClause;
|
||||
}
|
||||
|
||||
public String getJoinClause() {
|
||||
return joinClause;
|
||||
}
|
||||
|
||||
public void setJoinClause(String joinClause) {
|
||||
this.joinClause = joinClause;
|
||||
}
|
||||
|
||||
public Set<String> targetScreensSet() {
|
||||
if (StringUtils.isNotBlank(targetScreens)) {
|
||||
return new HashSet<>(Arrays.asList(targetScreens.split(",")));
|
||||
|
@ -104,6 +104,8 @@ CategoryAttribute.targetScreens = Target screens
|
||||
CategoryAttribute.defaultDateIsCurrent = Default date is current
|
||||
CategoryAttribute.width=Width
|
||||
CategoryAttribute.rowsCount=Rows count
|
||||
CategoryAttribute.joinClause=Join clause
|
||||
CategoryAttribute.whereClause=Where clause
|
||||
|
||||
ScheduledTask=Scheduled Task
|
||||
ScheduledTask.beanName=Bean Name
|
||||
|
@ -32,6 +32,8 @@ import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.gui.ScreensHelper;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.components.actions.RemoveAction;
|
||||
import com.haulmont.cuba.gui.components.autocomplete.JpqlSuggestionFactory;
|
||||
import com.haulmont.cuba.gui.components.autocomplete.Suggestion;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.DataSupplier;
|
||||
@ -53,6 +55,7 @@ import java.util.*;
|
||||
public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
protected static final Multimap<PropertyType, String> FIELDS_VISIBLE_FOR_DATATYPES = ArrayListMultimap.create();
|
||||
protected static final Set<String> ALWAYS_VISIBLE_FIELDS = new HashSet<>(Arrays.asList("name", "code", "required", "dataType", "isCollection"));
|
||||
protected static final String WHERE = " where ";
|
||||
|
||||
static {
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.BOOLEAN, "defaultBoolean");
|
||||
@ -74,6 +77,8 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.ENTITY, "lookup");
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.ENTITY, "defaultEntityId");
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.ENTITY, "width");
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.ENTITY, "joinClause");
|
||||
FIELDS_VISIBLE_FOR_DATATYPES.put(PropertyType.ENTITY, "whereClause");
|
||||
}
|
||||
|
||||
protected CategoryAttribute attribute;
|
||||
@ -129,6 +134,8 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
protected CollectionDatasource<ScreenAndComponent, UUID> screensDs;
|
||||
|
||||
private ListEditor enumerationListEditor;
|
||||
private SourceCodeEditor joinField;
|
||||
private SourceCodeEditor whereField;
|
||||
|
||||
@Override
|
||||
public void init(Map<String, Object> params) {
|
||||
@ -257,6 +264,28 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
return enumerationListEditor;
|
||||
});
|
||||
|
||||
attributeFieldGroup.addCustomField("whereClause", (datasource, propertyId) -> {
|
||||
whereField = factory.createComponent(SourceCodeEditor.class);
|
||||
whereField.setDatasource(attributeDs, "whereClause");
|
||||
whereField.setWidth("100%");
|
||||
whereField.setHeight(themeConstants.get("cuba.gui.customConditionFrame.whereField.height"));
|
||||
whereField.setSuggester((source, text, cursorPosition) -> requestHint(whereField, text, cursorPosition));
|
||||
whereField.setHighlightActiveLine(false);
|
||||
whereField.setShowGutter(false);
|
||||
return whereField;
|
||||
});
|
||||
|
||||
attributeFieldGroup.addCustomField("joinClause", (datasource, propertyId) -> {
|
||||
joinField = factory.createComponent(SourceCodeEditor.class);
|
||||
joinField.setDatasource(attributeDs, "joinClause");
|
||||
joinField.setWidth("100%");
|
||||
joinField.setHeight(themeConstants.get("cuba.gui.customConditionFrame.joinField.height"));
|
||||
joinField.setSuggester((source, text, cursorPosition) -> requestHint(joinField, text, cursorPosition));
|
||||
joinField.setHighlightActiveLine(false);
|
||||
joinField.setShowGutter(false);
|
||||
return joinField;
|
||||
});
|
||||
|
||||
attributeDs.addItemPropertyChangeListener(e -> {
|
||||
String property = e.getProperty();
|
||||
CategoryAttribute attribute = getItem();
|
||||
@ -269,9 +298,8 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
if ("name".equalsIgnoreCase(property)) {
|
||||
fillAttributeCode();
|
||||
}
|
||||
if ("screen".equalsIgnoreCase(property)) {
|
||||
dynamicAttributesGuiTools.initEntityLookupAction(entityLookupAction,
|
||||
metadata.getClass(attribute.getJavaClassForEntity()), attribute.getScreen());
|
||||
if ("screen".equalsIgnoreCase(property) || "joinClause".equals(property) || "whereClause".equals(property)) {
|
||||
dynamicAttributesGuiTools.initEntityPickerField(defaultEntityField, attribute);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -298,7 +326,8 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
defaultEntityField.setMetaClass(metaClass);
|
||||
fillDefaultEntities(entityClass);
|
||||
fillSelectEntityScreens(entityClass);
|
||||
dynamicAttributesGuiTools.initEntityLookupAction(entityLookupAction, metaClass, attribute.getScreen());
|
||||
|
||||
dynamicAttributesGuiTools.initEntityPickerField(defaultEntityField, attribute);
|
||||
} else {
|
||||
defaultEntityField.setEditable(false);
|
||||
}
|
||||
@ -448,4 +477,37 @@ public class AttributeEditor extends AbstractEditor<CategoryAttribute> {
|
||||
|
||||
setupVisibility();
|
||||
}
|
||||
|
||||
protected List<Suggestion> requestHint(SourceCodeEditor sender, String text, int senderCursorPosition) {
|
||||
String joinStr = joinField.getValue();
|
||||
String whereStr = whereField.getValue();
|
||||
|
||||
// CAUTION: the magic entity name! The length is three character to match "{E}" length in query
|
||||
String entityAlias = "a39";
|
||||
|
||||
int queryPosition = -1;
|
||||
Class javaClassForEntity = attribute.getJavaClassForEntity();
|
||||
if (javaClassForEntity == null) return new ArrayList<>();
|
||||
|
||||
MetaClass metaClass = metadata.getClassNN(javaClassForEntity);
|
||||
String queryStart = "select " + entityAlias + " from " + metaClass.getName() + " " + entityAlias + " ";
|
||||
|
||||
StringBuilder queryBuilder = new StringBuilder(queryStart);
|
||||
if (joinStr != null && !joinStr.equals("")) {
|
||||
if (sender == joinField) {
|
||||
queryPosition = queryBuilder.length() + senderCursorPosition - 1;
|
||||
}
|
||||
queryBuilder.append(joinStr);
|
||||
}
|
||||
if (whereStr != null && !whereStr.equals("")) {
|
||||
if (sender == whereField) {
|
||||
queryPosition = queryBuilder.length() + WHERE.length() + senderCursorPosition - 1;
|
||||
}
|
||||
queryBuilder.append(WHERE).append(whereStr);
|
||||
}
|
||||
String query = queryBuilder.toString();
|
||||
query = query.replace("{E}", entityAlias);
|
||||
|
||||
return JpqlSuggestionFactory.requestHint(query, queryPosition, sender.getAutoCompleteSupport(), senderCursorPosition);
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@
|
||||
<field id="entityClass" custom="true" required="true" width="100%"/>
|
||||
<field id="screen" custom="true" width="100%"/>
|
||||
<field id="lookup"/>
|
||||
<field id="joinClause" width="100%" custom="true"/>
|
||||
<field id="whereClause" width="100%" rows="3" custom="true"/>
|
||||
<field id="width" width="100%">
|
||||
<validator class="com.haulmont.cuba.gui.components.validators.PatternValidator"
|
||||
pattern="^(\d*(\.\d+)?)(%|px)?$" message="msg://widthValidationMsg"/>
|
||||
|
@ -31,12 +31,10 @@ import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.FileDescriptor;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.global.View;
|
||||
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.DsBuilder;
|
||||
import com.haulmont.cuba.gui.data.RuntimePropsDatasource;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
@ -334,25 +332,25 @@ public abstract class AbstractFieldFactory implements FieldFactory {
|
||||
DynamicAttributesMetaProperty metaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
CategoryAttribute attribute = metaProperty.getAttribute();
|
||||
if (Boolean.TRUE.equals(attribute.getLookup())) {
|
||||
optionsDatasource = new DsBuilder(datasource.getDsContext())
|
||||
.setMetaClass(metaProperty.getRange().asClass())
|
||||
.setViewName(View.MINIMAL)
|
||||
.buildCollectionDatasource();
|
||||
optionsDatasource.refresh();
|
||||
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.LookupAction lookupAction = pickerField.addLookupAction();
|
||||
pickerField.setDatasource(datasource, property);
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(mpp.getMetaProperty())) {
|
||||
DynamicAttributesGuiTools dynamicAttributesGuiTools = AppBeans.get(DynamicAttributesGuiTools.class);
|
||||
dynamicAttributesGuiTools.initEntityLookupAction(lookupAction, (DynamicAttributesMetaProperty) mpp.getMetaProperty());
|
||||
DynamicAttributesMetaProperty dynamicAttributesMetaProperty = (DynamicAttributesMetaProperty) mpp.getMetaProperty();
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField, dynamicAttributesMetaProperty.getAttribute());
|
||||
}
|
||||
pickerField.addClearAction();
|
||||
} else {
|
||||
LookupPickerField lookupPickerField = componentsFactory.createComponent(LookupPickerField.class);
|
||||
lookupPickerField.setDatasource(datasource, property);
|
||||
lookupPickerField.setOptionsDatasource(optionsDatasource);
|
||||
|
||||
pickerField = lookupPickerField;
|
||||
@ -368,8 +366,6 @@ public abstract class AbstractFieldFactory implements FieldFactory {
|
||||
}
|
||||
}
|
||||
|
||||
pickerField.setDatasource(datasource, property);
|
||||
|
||||
return pickerField;
|
||||
} else {
|
||||
EntityLinkField linkField = componentsFactory.createComponent(EntityLinkField.class);
|
||||
|
@ -55,6 +55,14 @@ public interface ListEditor extends Field {
|
||||
*/
|
||||
void setOptionsList(List<Object> optionsList);
|
||||
|
||||
String getEntityJoinClause();
|
||||
|
||||
void setEntityJoinClause(String entityJoinClause);
|
||||
|
||||
String getEntityWhereClause();
|
||||
|
||||
void setEntityWhereClause(String entityWhereClause);
|
||||
|
||||
enum ItemType {
|
||||
STRING,
|
||||
DATE,
|
||||
|
@ -331,9 +331,12 @@ public interface PickerField extends Field, Component.ActionsHolder {
|
||||
afterLookupCloseHandler.onClose(lookupWindow, actionId);
|
||||
}
|
||||
});
|
||||
afterLookupWindowOpened(lookupWindow);
|
||||
}
|
||||
}
|
||||
|
||||
protected void afterLookupWindowOpened(Window lookupWindow) {}
|
||||
|
||||
/**
|
||||
* Hook to be implemented in subclasses. Called by the action for new value selected from Lookup window.
|
||||
* Can be used for reloading of entity with different view or to replace value with another value.
|
||||
|
@ -31,14 +31,11 @@ import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.global.DevelopmentException;
|
||||
import com.haulmont.cuba.core.global.View;
|
||||
import com.haulmont.cuba.gui.AppConfig;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.WindowParam;
|
||||
import com.haulmont.cuba.gui.commonlookup.CommonLookupController;
|
||||
import com.haulmont.cuba.gui.components.validators.DateValidator;
|
||||
import com.haulmont.cuba.gui.components.validators.DoubleValidator;
|
||||
import com.haulmont.cuba.gui.components.validators.IntegerValidator;
|
||||
import com.haulmont.cuba.gui.components.validators.LongValidator;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.data.DsBuilder;
|
||||
@ -48,7 +45,10 @@ import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.haulmont.cuba.gui.components.PickerField.LookupAction;
|
||||
|
||||
@ -252,8 +252,7 @@ public class RuntimePropertiesFrame extends AbstractWindow {
|
||||
((LookupPickerField) pickerField).setOptionsDatasource(optionsDs);
|
||||
} else {
|
||||
pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
LookupAction lookupAction = pickerField.addLookupAction();
|
||||
dynamicAttributesGuiTools.initEntityLookupAction(lookupAction, metaProperty);
|
||||
dynamicAttributesGuiTools.initEntityPickerField(pickerField, metaProperty.getAttribute());
|
||||
}
|
||||
pickerField.setMetaClass(ds.getMetaClass());
|
||||
pickerField.setFrame(RuntimePropertiesFrame.this);
|
||||
|
@ -56,4 +56,12 @@ public interface ListEditorDelegate {
|
||||
void setOptionsList(List<Object> optionsList);
|
||||
|
||||
void setDisplayDescription(boolean displayDescription);
|
||||
|
||||
String getEntityJoinClause();
|
||||
|
||||
void setEntityJoinClause(String entityJoinClause);
|
||||
|
||||
String getEntityWhereClause();
|
||||
|
||||
void setEntityWhereClause(String entityWhereClause);
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ public class ListEditorDelegateImpl implements ListEditorDelegate{
|
||||
protected String lookupScreen;
|
||||
protected boolean useLookupField;
|
||||
protected List<Object> optionsList;
|
||||
protected String entityJoinClause;
|
||||
protected String entityWhereClause;
|
||||
|
||||
protected TextField displayValuesField;
|
||||
protected HBoxLayout layout;
|
||||
@ -88,6 +90,8 @@ public class ListEditorDelegateImpl implements ListEditorDelegate{
|
||||
params.put("useLookupField", useLookupField);
|
||||
params.put("optionsList", optionsList);
|
||||
params.put("lookupScreen", lookupScreen);
|
||||
params.put("entityJoinClause", entityJoinClause);
|
||||
params.put("entityWhereClause", entityWhereClause);
|
||||
params.put("values", getValue());
|
||||
ListEditorPopupWindow listEditorPopup = (ListEditorPopupWindow) windowManager
|
||||
.openWindow(windowConfig.getWindowInfo("list-editor-popup"), WindowManager.OpenType.DIALOG, params);
|
||||
@ -190,4 +194,24 @@ public class ListEditorDelegateImpl implements ListEditorDelegate{
|
||||
public void setDisplayDescription(boolean displayDescription) {
|
||||
this.displayDescription = displayDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityJoinClause() {
|
||||
return entityJoinClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityJoinClause(String entityJoinClause) {
|
||||
this.entityJoinClause = entityJoinClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityWhereClause() {
|
||||
return entityWhereClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityWhereClause(String entityWhereClause) {
|
||||
this.entityWhereClause = entityWhereClause;
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,14 @@ import com.haulmont.chile.core.datatypes.Datatype;
|
||||
import com.haulmont.chile.core.datatypes.Datatypes;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Metadata;
|
||||
import com.haulmont.cuba.core.global.View;
|
||||
import com.haulmont.cuba.gui.WindowParam;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.DsBuilder;
|
||||
import com.haulmont.cuba.gui.dynamicattributes.DynamicAttributesGuiTools;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstants;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
@ -63,6 +65,12 @@ public class ListEditorPopupWindow extends AbstractWindow {
|
||||
@WindowParam
|
||||
protected Boolean useLookupField;
|
||||
|
||||
@WindowParam
|
||||
protected String entityJoinClause;
|
||||
|
||||
@WindowParam
|
||||
protected String entityWhereClause;
|
||||
|
||||
@WindowParam(required = true)
|
||||
protected ListEditor.ItemType itemType;
|
||||
|
||||
@ -78,6 +86,9 @@ public class ListEditorPopupWindow extends AbstractWindow {
|
||||
@Inject
|
||||
protected ThemeConstants theme;
|
||||
|
||||
@Inject
|
||||
protected DynamicAttributesGuiTools dynamicAttributesGuiTools;
|
||||
|
||||
protected Map<Object, String> valuesMap;
|
||||
|
||||
@Override
|
||||
@ -179,22 +190,33 @@ public class ListEditorPopupWindow extends AbstractWindow {
|
||||
Field componentForEntity;
|
||||
if (BooleanUtils.isNotTrue(useLookupField)) {
|
||||
PickerField pickerField = componentsFactory.createComponent(PickerField.class);
|
||||
if (!Strings.isNullOrEmpty(lookupScreen)) {
|
||||
PickerField.LookupAction lookupAction = (PickerField.LookupAction) pickerField.getAction(PickerField.LookupAction.NAME);
|
||||
if (lookupAction != null) {
|
||||
lookupAction.setLookupScreen(lookupScreen);
|
||||
}
|
||||
}
|
||||
pickerField.addLookupAction();
|
||||
pickerField.setMetaClass(metaClass);
|
||||
|
||||
if (!Strings.isNullOrEmpty(entityJoinClause) || !Strings.isNullOrEmpty(entityWhereClause)) {
|
||||
PickerField.LookupAction lookupAction = dynamicAttributesGuiTools.createLookupAction(pickerField, entityJoinClause, entityWhereClause);
|
||||
pickerField.addAction(lookupAction);
|
||||
} else {
|
||||
if (!Strings.isNullOrEmpty(lookupScreen)) {
|
||||
PickerField.LookupAction lookupAction = (PickerField.LookupAction) pickerField.getAction(PickerField.LookupAction.NAME);
|
||||
if (lookupAction != null) {
|
||||
lookupAction.setLookupScreen(lookupScreen);
|
||||
}
|
||||
}
|
||||
pickerField.addLookupAction();
|
||||
}
|
||||
componentForEntity = pickerField;
|
||||
} else {
|
||||
LookupField lookupField = componentsFactory.createComponent(LookupField.class);
|
||||
CollectionDatasource optionsDs = new DsBuilder()
|
||||
.setMetaClass(metaClass)
|
||||
.setViewName(View.MINIMAL)
|
||||
.buildCollectionDatasource();
|
||||
optionsDs.refresh();
|
||||
CollectionDatasource optionsDs;
|
||||
if (!Strings.isNullOrEmpty(entityJoinClause) || !Strings.isNullOrEmpty(entityWhereClause)) {
|
||||
optionsDs = dynamicAttributesGuiTools.createOptionsDatasourceForLookup(metaClass, entityJoinClause, entityWhereClause);
|
||||
} else {
|
||||
optionsDs = new DsBuilder()
|
||||
.setMetaClass(metaClass)
|
||||
.setViewName(View.MINIMAL)
|
||||
.buildCollectionDatasource();
|
||||
optionsDs.refresh();
|
||||
}
|
||||
lookupField.setOptionsDatasource(optionsDs);
|
||||
componentForEntity = lookupField;
|
||||
}
|
||||
|
@ -24,7 +24,9 @@ import com.haulmont.cuba.core.app.dynamicattributes.PropertyType;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.Metadata;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.components.Component;
|
||||
import com.haulmont.cuba.gui.components.FieldGroup;
|
||||
import com.haulmont.cuba.gui.components.ListEditor;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
@ -57,6 +59,9 @@ public class DynamicAttributeCustomFieldGenerator implements FieldGroup.CustomFi
|
||||
return null;
|
||||
}
|
||||
|
||||
listEditor.setEntityJoinClause(categoryAttribute.getJoinClause());
|
||||
listEditor.setEntityWhereClause(categoryAttribute.getWhereClause());
|
||||
|
||||
ListEditor.ItemType itemType = listEditorItemTypeFromDynamicAttrType(categoryAttribute.getDataType());
|
||||
listEditor.setItemType(itemType);
|
||||
Metadata metadata = AppBeans.get(Metadata.class);
|
||||
|
@ -17,23 +17,27 @@
|
||||
|
||||
package com.haulmont.cuba.gui.dynamicattributes;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
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.cuba.core.app.dynamicattributes.DynamicAttributes;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesMetaProperty;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.entity.BaseGenericIdEntity;
|
||||
import com.haulmont.cuba.core.entity.Categorized;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.MetadataTools;
|
||||
import com.haulmont.cuba.core.global.TimeSource;
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.gui.WindowManager;
|
||||
import com.haulmont.cuba.gui.WindowParams;
|
||||
import com.haulmont.cuba.gui.commonlookup.CommonLookupController;
|
||||
import com.haulmont.cuba.gui.components.PickerField;
|
||||
import com.haulmont.cuba.gui.config.WindowConfig;
|
||||
import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.data.Datasource;
|
||||
import com.haulmont.cuba.gui.data.DsBuilder;
|
||||
import com.haulmont.cuba.gui.data.impl.DatasourceImplementation;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -55,6 +59,9 @@ public class DynamicAttributesGuiTools {
|
||||
@Inject
|
||||
protected WindowConfig windowConfig;
|
||||
|
||||
@Inject
|
||||
protected Metadata metadata;
|
||||
|
||||
/**
|
||||
* Enforce the datasource to change modified status if dynamic attribute is changed
|
||||
*/
|
||||
@ -125,11 +132,31 @@ public class DynamicAttributesGuiTools {
|
||||
});
|
||||
}
|
||||
|
||||
public void initEntityLookupAction(PickerField.LookupAction lookupAction, DynamicAttributesMetaProperty metaProperty) {
|
||||
initEntityLookupAction(lookupAction, metaProperty.getRange().asClass(), metaProperty.getAttribute().getScreen());
|
||||
protected boolean attributeShouldBeShownOnTheScreen(String screen, String component, CategoryAttribute attribute) {
|
||||
Set<String> targetScreensSet = attribute.targetScreensSet();
|
||||
return targetScreensSet.contains(screen) || targetScreensSet.contains(screen + "#" + component);
|
||||
}
|
||||
|
||||
public void initEntityLookupAction(PickerField.LookupAction lookupAction, MetaClass metaClass, String screen) {
|
||||
/**
|
||||
* Initializes the pickerField for selecting the dynamic attribute value. If the CategoryAttribute has "where" or
|
||||
* "join" clauses then the data in lookup screens will be filtered with these clauses
|
||||
*
|
||||
* @param pickerField PickerField component whose lookup action must be initialized
|
||||
* @param categoryAttribute CategoryAttribute that is represented by the pickerField
|
||||
*/
|
||||
public void initEntityPickerField(PickerField pickerField, CategoryAttribute categoryAttribute) {
|
||||
Class javaClass = categoryAttribute.getJavaClassForEntity();
|
||||
if (javaClass == null) {
|
||||
throw new IllegalArgumentException("Entity type is not specified in category attribute");
|
||||
}
|
||||
MetaClass metaClass = metadata.getClassNN(javaClass);
|
||||
PickerField.LookupAction lookupAction = (PickerField.LookupAction) pickerField.getAction(PickerField.LookupAction.NAME);
|
||||
if (!Strings.isNullOrEmpty(categoryAttribute.getJoinClause()) || !Strings.isNullOrEmpty(categoryAttribute.getWhereClause())) {
|
||||
lookupAction = createLookupAction(pickerField, categoryAttribute.getJoinClause(), categoryAttribute.getWhereClause());
|
||||
pickerField.addAction(lookupAction);
|
||||
}
|
||||
|
||||
String screen = categoryAttribute.getScreen();
|
||||
if (StringUtils.isBlank(screen)) {
|
||||
screen = windowConfig.getBrowseScreenId(metaClass);
|
||||
if (windowConfig.findWindowInfo(screen) != null) {
|
||||
@ -145,8 +172,43 @@ public class DynamicAttributesGuiTools {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean attributeShouldBeShownOnTheScreen(String screen, String component, CategoryAttribute attribute) {
|
||||
Set<String> targetScreensSet = attribute.targetScreensSet();
|
||||
return targetScreensSet.contains(screen) || targetScreensSet.contains(screen + "#" + component);
|
||||
/**
|
||||
* Creates the collection datasource that is used for selecting the dynamic attribute value. If the
|
||||
* CategoryAttribute has "where" or "join" clauses then only items that satisfy these clauses will be presented in
|
||||
* the options datasource
|
||||
*/
|
||||
public CollectionDatasource createOptionsDatasourceForLookup(MetaClass metaClass, String joinClause, String whereClause) {
|
||||
CollectionDatasource optionsDatasource = new DsBuilder()
|
||||
.setMetaClass(metaClass)
|
||||
.setViewName(View.MINIMAL)
|
||||
.buildCollectionDatasource();
|
||||
|
||||
String query = "select e from " + metaClass.getName() + " e";
|
||||
|
||||
if (!Strings.isNullOrEmpty(joinClause)) {
|
||||
query += " " + joinClause;
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(whereClause)) {
|
||||
query += " where " + whereClause.replaceAll("\\{E\\}", "e");
|
||||
}
|
||||
|
||||
optionsDatasource.setQuery(query);
|
||||
optionsDatasource.refresh();
|
||||
return optionsDatasource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the lookup action that will open the lookup screen with the dynamic filter applied. This filter contains
|
||||
* a condition with join and where clauses
|
||||
*/
|
||||
public PickerField.LookupAction createLookupAction(PickerField pickerField,
|
||||
String joinClause,
|
||||
String whereClause) {
|
||||
FilteringLookupAction filteringLookupAction = new FilteringLookupAction(pickerField, joinClause, whereClause);
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
WindowParams.DISABLE_RESUME_SUSPENDED.set(params, true);
|
||||
WindowParams.DISABLE_AUTO_REFRESH.set(params, true);
|
||||
filteringLookupAction.setLookupScreenParams(params);
|
||||
return filteringLookupAction;
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2016 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.dynamicattributes;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.haulmont.bali.datastruct.Node;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
import com.haulmont.cuba.core.global.ExtendedEntities;
|
||||
import com.haulmont.cuba.core.global.Messages;
|
||||
import com.haulmont.cuba.core.global.Metadata;
|
||||
import com.haulmont.cuba.gui.AppConfig;
|
||||
import com.haulmont.cuba.gui.ComponentsHelper;
|
||||
import com.haulmont.cuba.gui.components.*;
|
||||
import com.haulmont.cuba.gui.components.filter.ConditionParamBuilder;
|
||||
import com.haulmont.cuba.gui.components.filter.ConditionsTree;
|
||||
import com.haulmont.cuba.gui.components.filter.FilterParser;
|
||||
import com.haulmont.cuba.gui.components.filter.Param;
|
||||
import com.haulmont.cuba.gui.components.filter.condition.CustomCondition;
|
||||
import com.haulmont.cuba.gui.data.impl.DsContextImplementation;
|
||||
import com.haulmont.cuba.security.entity.FilterEntity;
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Extended PickerField.LookupAction. This action requires "join" and "where" clauses. When the lookup screen is
|
||||
* opened these clauses are used for creating dynamic filter condition in the Filter component. So the data in the
|
||||
* lookup screen is filtered.
|
||||
*/
|
||||
public class FilteringLookupAction extends PickerField.LookupAction {
|
||||
|
||||
private ExtendedEntities extendedEntities;
|
||||
private String joinClause;
|
||||
private String whereClause;
|
||||
|
||||
public FilteringLookupAction(PickerField pickerField, String joinClause, String whereClause) {
|
||||
super(pickerField);
|
||||
this.joinClause = joinClause;
|
||||
this.whereClause = whereClause;
|
||||
Preconditions.checkNotNull(pickerField.getMetaClass(), "MetaClass for PickerField is not set");
|
||||
extendedEntities = AppBeans.get(ExtendedEntities.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterLookupWindowOpened(Window lookupWindow) {
|
||||
boolean found = ComponentsHelper.walkComponents(lookupWindow, screenComponent -> {
|
||||
if (!(screenComponent instanceof Filter)) {
|
||||
return false;
|
||||
} else {
|
||||
MetaClass actualMetaClass = ((Filter) screenComponent).getDatasource().getMetaClass();
|
||||
MetaClass propertyMetaClass = extendedEntities.getEffectiveMetaClass(pickerField.getMetaClass());
|
||||
if (ObjectUtils.equals(actualMetaClass, propertyMetaClass)) {
|
||||
applyFilter(((Filter) screenComponent));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (!found) {
|
||||
target.getFrame().showNotification(messages.getMainMessage("dynamicAttributes.entity.filter.filterNotFound"), Frame.NotificationType.WARNING);
|
||||
}
|
||||
((DsContextImplementation) lookupWindow.getDsContext()).resumeSuspended();
|
||||
}
|
||||
|
||||
protected void applyFilter(Filter filterComponent) {
|
||||
Metadata metadata = AppBeans.get(Metadata.class);
|
||||
FilterEntity filterEntity = metadata.create(FilterEntity.class);
|
||||
filterEntity.setComponentId(ComponentsHelper.getFilterComponentPath(filterComponent));
|
||||
filterEntity.setName(messages.getMainMessage("dynamicAttributes.entity.filter"));
|
||||
filterEntity.setXml(createFilterXml(filterComponent));
|
||||
filterEntity.setUser(userSession.getCurrentOrSubstitutedUser());
|
||||
|
||||
filterComponent.setFilterEntity(filterEntity);
|
||||
filterComponent.apply(true);
|
||||
}
|
||||
|
||||
protected String createFilterXml(Filter filterComponent) {
|
||||
ConditionsTree tree = new ConditionsTree();
|
||||
CustomCondition condition = createCustomCondition(filterComponent);
|
||||
tree.setRootNodes(Collections.singletonList(new Node<>(condition)));
|
||||
return AppBeans.get(FilterParser.class).getXml(tree, Param.ValueProperty.VALUE);
|
||||
}
|
||||
|
||||
protected CustomCondition createCustomCondition(Filter filterComponent) {
|
||||
CustomCondition condition = new CustomCondition(createConditionXmlElement(),
|
||||
AppConfig.getMessagesPack(),
|
||||
getFilterComponentName(filterComponent),
|
||||
filterComponent.getDatasource());
|
||||
|
||||
condition.setUnary(true);
|
||||
condition.setHidden(true);
|
||||
|
||||
condition.setWhere(whereClause.replaceAll("\\?", ":" + condition.getParamName()));
|
||||
condition.setJoin(joinClause);
|
||||
|
||||
ConditionParamBuilder paramBuilder = AppBeans.get(ConditionParamBuilder.class);
|
||||
Param param = Param.Builder.getInstance().setName(paramBuilder.createParamName(condition))
|
||||
.setJavaClass(Boolean.class)
|
||||
.setEntityWhere("")
|
||||
.setEntityView("")
|
||||
.setDataSource(filterComponent.getDatasource())
|
||||
.setInExpr(true)
|
||||
.setRequired(true)
|
||||
.build();
|
||||
param.setValue(true);
|
||||
condition.setParam(param);
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
protected Element createConditionXmlElement() {
|
||||
Element conditionElement = DocumentHelper.createDocument().addElement("c");
|
||||
conditionElement.addAttribute("name", RandomStringUtils.randomAlphabetic(10));
|
||||
conditionElement.addAttribute("width", "1");
|
||||
conditionElement.addAttribute("type", "CUSTOM");
|
||||
conditionElement.addAttribute("locCaption", messages.getMainMessage("dynamicAttributes.filter.conditionName"));
|
||||
return conditionElement;
|
||||
}
|
||||
|
||||
protected String getFilterComponentName(Filter filterComponent) {
|
||||
String filterComponentPath = ComponentsHelper.getFilterComponentPath(filterComponent);
|
||||
String[] strings = ValuePathHelper.parse(filterComponentPath);
|
||||
return ValuePathHelper.format(Arrays.copyOfRange(strings, 1, strings.length));
|
||||
}
|
||||
}
|
@ -311,6 +311,9 @@ excelExporter.false=No
|
||||
excelExporter.empty=[Empty]
|
||||
|
||||
dynamicAttributes.category=Category
|
||||
dynamicAttributes.entity.filter=Restricting dynamic filter
|
||||
dynamicAttributes.filter.conditionName=Dynamic condition
|
||||
dynamicAttributes.entity.filter.filterNotFound=Filter component not found
|
||||
|
||||
searchSelect.notFound=Not found items for filter: %s
|
||||
searchSelect.minimumLengthOfFilter=Minimum length of search string is %s
|
||||
|
@ -311,6 +311,10 @@ actions.export.ALL_ROWS=Все строки
|
||||
actions.export.SELECTED_ROWS=Выбранные строки
|
||||
|
||||
dynamicAttributes.category=Категория
|
||||
dynamicAttributes.entity.filter=Ограничивающий фильтр
|
||||
dynamicAttributes.filter.conditionName=Динамическое условие
|
||||
dynamicAttributes.entity.filter.filterNotFound=Компонент фильтра не найден
|
||||
|
||||
mssqlDateOutOfRangeException.message=Допустимы даты в промежутке от 1 января 1753 до 31 декабря 9999
|
||||
|
||||
searchSelect.notFound=Не найдено записей для фильтра: %s
|
||||
|
@ -93,6 +93,26 @@ public class WebListEditor extends WebAbstractField<WebListEditor.CubaListEditor
|
||||
delegate.setOptionsList(optionsList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityJoinClause() {
|
||||
return delegate.getEntityJoinClause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityJoinClause(String entityJoinClause) {
|
||||
delegate.setEntityJoinClause(entityJoinClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityWhereClause() {
|
||||
return delegate.getEntityWhereClause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityWhereClause(String entityWhereClause) {
|
||||
delegate.setEntityWhereClause(entityWhereClause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object newValue) {
|
||||
if (!(newValue instanceof List)) {
|
||||
|
Loading…
Reference in New Issue
Block a user