New presentation data layer #474

Add data.xsd, change 'container' attribute name to 'dataContainer'
This commit is contained in:
Konstantin Krivopustov 2018-09-25 18:12:01 +04:00
parent 7fe506d804
commit f7cb088fcb
26 changed files with 527 additions and 98 deletions

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2008-2018 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.model;
import com.haulmont.cuba.core.global.Sort;
public interface BaseCollectionLoader extends DataLoader {
CollectionContainer getContainer();
/**
* The position of the first instance to load, numbered from 0.
* Returns 0 if {@link #setFirstResult(int)} was not called.
*/
int getFirstResult();
/**
* Sets the position of the first instance to load, numbered from 0.
*/
void setFirstResult(int firstResult);
/**
* The maximum number of instances to load.
* Returns {@code Integer.MAX_VALUE} if {@link #setMaxResults} was not called.
*/
int getMaxResults();
/**
* Sets the maximum number of instances to load.
*/
void setMaxResults(int maxResults);
Sort getSort();
void setSort(Sort sort);
}

View File

@ -18,7 +18,6 @@ package com.haulmont.cuba.gui.model;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Sort;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.screen.InstallSubject;
@ -29,7 +28,7 @@ import java.util.function.Function;
*
*/
@InstallSubject("loadDelegate")
public interface CollectionLoader<E extends Entity> extends DataLoader {
public interface CollectionLoader<E extends Entity> extends BaseCollectionLoader {
CollectionContainer<E> getContainer();
@ -37,28 +36,6 @@ public interface CollectionLoader<E extends Entity> extends DataLoader {
LoadContext<E> createLoadContext();
/**
* The position of the first instance to load, numbered from 0.
* Returns 0 if {@link #setFirstResult(int)} was not called.
*/
int getFirstResult();
/**
* Sets the position of the first instance to load, numbered from 0.
*/
void setFirstResult(int firstResult);
/**
* The maximum number of instances to load.
* Returns {@code Integer.MAX_VALUE} if {@link #setMaxResults} was not called.
*/
int getMaxResults();
/**
* Sets the maximum number of instances to load.
*/
void setMaxResults(int maxResults);
boolean isLoadDynamicAttributes();
void setLoadDynamicAttributes(boolean loadDynamicAttributes);
@ -73,10 +50,6 @@ public interface CollectionLoader<E extends Entity> extends DataLoader {
void setView(String viewName);
Sort getSort();
void setSort(Sort sort);
/**
* Returns a function which will be used to load data instead of standard implementation.
*/

View File

@ -27,38 +27,18 @@ import java.util.function.Function;
*
*/
@InstallSubject("loadDelegate")
public interface KeyValueCollectionLoader extends DataLoader {
public interface KeyValueCollectionLoader extends BaseCollectionLoader {
KeyValueCollectionContainer getContainer();
void setContainer(KeyValueCollectionContainer container);
ValueLoadContext createLoadContext();
String getStoreName();
void setStoreName(String name);
/**
* The position of the first instance to load, numbered from 0.
* Returns 0 if {@link #setFirstResult(int)} was not called.
*/
int getFirstResult();
/**
* Sets the position of the first instance to load, numbered from 0.
*/
void setFirstResult(int firstResult);
/**
* The maximum number of instances to load.
* Returns {@code Integer.MAX_VALUE} if {@link #setMaxResults} was not called.
*/
int getMaxResults();
/**
* Sets the maximum number of instances to load.
*/
void setMaxResults(int maxResults);
/**
* Returns a function which will be used to load data instead of standard implementation.
*/

View File

@ -16,7 +16,6 @@
package com.haulmont.cuba.gui.model;
import javax.annotation.Nullable;
import java.util.Set;
public interface ScreenData {

View File

@ -21,8 +21,8 @@ import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.Sort;
import com.haulmont.cuba.gui.data.impl.EntityComparator;
import com.haulmont.cuba.gui.model.BaseCollectionLoader;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.model.Sorter;
import java.util.ArrayList;
@ -35,10 +35,10 @@ import java.util.List;
public class CollectionContainerSorter implements Sorter {
private final CollectionContainer<Entity> container;
private final CollectionLoader<Entity> loader;
private final BaseCollectionLoader loader;
@SuppressWarnings("unchecked")
public CollectionContainerSorter(CollectionLoader loader) {
public CollectionContainerSorter(BaseCollectionLoader loader) {
this.container = loader.getContainer();
if (this.container == null) {
throw new IllegalStateException("Container is not set for the loader");

View File

@ -19,8 +19,11 @@ package com.haulmont.cuba.gui.model.impl;
import com.google.common.base.Strings;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.bali.util.ReflectionHelper;
import com.haulmont.chile.core.datatypes.Datatype;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DevelopmentException;
import com.haulmont.cuba.core.global.MetadataTools;
import com.haulmont.cuba.core.global.ViewRepository;
import com.haulmont.cuba.core.global.queryconditions.Condition;
@ -58,6 +61,8 @@ public class ScreenDataXmlLoader {
loadCollectionContainer(screenData, el);
} else if (el.getName().equals("instance")) {
loadInstanceContainer(screenData, el);
} else if (el.getName().equals("keyValueCollection")) {
loadKeyValueCollectionContainer(screenData, el);
}
}
}
@ -98,6 +103,48 @@ public class ScreenDataXmlLoader {
}
}
protected void loadKeyValueCollectionContainer(ScreenData screenData, Element element) {
String containerId = getRequiredAttr(element, "id");
KeyValueCollectionContainer container = factory.createKeyValueCollectionContainer();
loadProperties(element, container);
String idName = element.attributeValue("idName");
if (!Strings.isNullOrEmpty(idName))
container.setIdName(idName);
Element loaderEl = element.element("loader");
if (loaderEl != null) {
loadKeyValueCollectionLoader(screenData, loaderEl, container);
}
screenData.registerContainer(containerId, container);
}
private void loadProperties(Element element, KeyValueCollectionContainer container) {
Element propsEl = element.element("properties");
if (propsEl != null) {
for (Element propEl : propsEl.elements()) {
String name = propEl.attributeValue("name");
String className = propEl.attributeValue("class");
if (className != null) {
container.addProperty(name, ReflectionHelper.getClass(className));
} else {
String typeName = propEl.attributeValue("datatype");
Datatype datatype = typeName == null ? Datatypes.getNN(String.class) : Datatypes.get(typeName);
container.addProperty(name, datatype);
}
}
String idProperty = propsEl.attributeValue("idProperty");
if (idProperty != null) {
if (container.getEntityMetaClass().getProperty(idProperty) == null)
throw new DevelopmentException(String.format("Property '%s' is not defined", idProperty));
container.setIdName(idProperty);
}
}
}
@SuppressWarnings("unchecked")
protected void loadNestedContainer(ScreenData screenData, Element element, InstanceContainer<Entity> parentContainer) {
if (!element.getName().equals("collection") && !element.getName().equals("instance"))
@ -153,6 +200,7 @@ public class ScreenDataXmlLoader {
loader.setContainer(container);
loadSoftDeletion(element, loader);
loadDynamicAttributes(element, loader);
loadQuery(element, loader);
loadEntityId(element, loader);
@ -169,6 +217,7 @@ public class ScreenDataXmlLoader {
loadQuery(element, loader);
loadSoftDeletion(element, loader);
loadDynamicAttributes(element, loader);
loadFirstResult(element, loader);
loadMaxResults(element, loader);
loadCacheable(element, loader);
@ -179,6 +228,25 @@ public class ScreenDataXmlLoader {
}
}
protected void loadKeyValueCollectionLoader(ScreenData screenData, Element element, KeyValueCollectionContainer container) {
KeyValueCollectionLoader loader = factory.createKeyValueCollectionLoader();
loader.setContainer(container);
loadQuery(element, loader);
loadSoftDeletion(element, loader);
loadFirstResult(element, loader);
loadMaxResults(element, loader);
String storeName = element.attributeValue("store");
if (!Strings.isNullOrEmpty(storeName))
loader.setStoreName(storeName);
String loaderId = element.attributeValue("id");
if (loaderId != null) {
screenData.registerLoader(loaderId, loader);
}
}
protected Class<Entity> getEntityClass(Element element) {
String entityClassName = getRequiredAttr(element, "class");
return ReflectionHelper.getClass(entityClassName);
@ -219,6 +287,17 @@ public class ScreenDataXmlLoader {
loader.setSoftDeletion(Boolean.valueOf(softDeletionVal));
}
protected void loadDynamicAttributes(Element element, DataLoader loader) {
String dynamicAttributes = element.attributeValue("dynamicAttributes");
if (!Strings.isNullOrEmpty(dynamicAttributes)) {
if (loader instanceof InstanceLoader) {
((InstanceLoader) loader).setLoadDynamicAttributes(Boolean.valueOf(dynamicAttributes));
} else if (loader instanceof CollectionLoader) {
((CollectionLoader) loader).setLoadDynamicAttributes(Boolean.valueOf(dynamicAttributes));
}
}
}
protected void loadEntityId(Element element, InstanceLoader<Entity> loader) {
String entityIdStr = element.attributeValue("entityId");
if (Strings.isNullOrEmpty(entityIdStr)) {
@ -240,7 +319,7 @@ public class ScreenDataXmlLoader {
}
}
protected void loadFirstResult(Element element, CollectionLoader<Entity> loader) {
protected void loadFirstResult(Element element, BaseCollectionLoader loader) {
String firstResultStr = element.attributeValue("firstResult");
if (Strings.isNullOrEmpty(firstResultStr))
return;
@ -248,7 +327,7 @@ public class ScreenDataXmlLoader {
loader.setFirstResult(Integer.valueOf(firstResultStr));
}
protected void loadMaxResults(Element element, CollectionLoader<Entity> loader) {
protected void loadMaxResults(Element element, BaseCollectionLoader loader) {
String maxResultsStr = element.attributeValue("maxResults");
if (Strings.isNullOrEmpty(maxResultsStr))
return;

View File

@ -19,10 +19,12 @@ package com.haulmont.cuba.gui.model.impl;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.cuba.core.entity.KeyValueEntity;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.Sort;
import com.haulmont.cuba.core.global.Stores;
import com.haulmont.cuba.core.global.ValueLoadContext;
import com.haulmont.cuba.core.global.queryconditions.Condition;
import com.haulmont.cuba.gui.model.DataContext;
import com.haulmont.cuba.gui.model.HasLoader;
import com.haulmont.cuba.gui.model.KeyValueCollectionContainer;
import com.haulmont.cuba.gui.model.KeyValueCollectionLoader;
import org.springframework.context.ApplicationContext;
@ -46,6 +48,7 @@ public class StandardKeyValueCollectionLoader implements KeyValueCollectionLoade
private int firstResult = 0;
private int maxResults = Integer.MAX_VALUE;
private boolean softDeletion = true;
private Sort sort;
private String storeName = Stores.MAIN;
private Function<ValueLoadContext, Collection<KeyValueEntity>> delegate;
@ -94,7 +97,8 @@ public class StandardKeyValueCollectionLoader implements KeyValueCollectionLoade
container.setItems(list);
}
protected ValueLoadContext createLoadContext() {
@Override
public ValueLoadContext createLoadContext() {
ValueLoadContext loadContext = ValueLoadContext.create();
loadContext.setStoreName(storeName);
loadContext.setIdName(container.getIdName());
@ -105,9 +109,12 @@ public class StandardKeyValueCollectionLoader implements KeyValueCollectionLoade
ValueLoadContext.Query query = loadContext.setQueryString(this.query);
query.setCondition(condition);
query.setSort(sort);
query.setParameters(parameters);
if (maxResults > 0)
if (firstResult > 0)
query.setFirstResult(firstResult);
if (maxResults < Integer.MAX_VALUE)
query.setMaxResults(maxResults);
loadContext.setSoftDeletion(softDeletion);
@ -122,6 +129,10 @@ public class StandardKeyValueCollectionLoader implements KeyValueCollectionLoade
@Override
public void setContainer(KeyValueCollectionContainer container) {
this.container = container;
if (container instanceof HasLoader) {
((HasLoader) container).setLoader(this);
}
container.setSorter(new CollectionContainerSorter(this));
}
@Override
@ -181,6 +192,20 @@ public class StandardKeyValueCollectionLoader implements KeyValueCollectionLoade
this.maxResults = maxResults;
}
@Override
public Sort getSort() {
return sort;
}
@Override
public void setSort(Sort sort) {
if (sort == null || sort.getOrders().isEmpty()) {
this.sort = null;
} else {
this.sort = sort;
}
}
@Override
public Function<ValueLoadContext, Collection<KeyValueEntity>> getDelegate() {
return delegate;

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2008-2018 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.
-->
<xs:schema targetNamespace="http://schemas.haulmont.com/cuba/screen/data.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.haulmont.com/cuba/screen/data.xsd"
elementFormDefault="qualified">
<xs:complexType name="screenData">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="instance" type="instanceContainerType"/>
<xs:element name="collection" type="collectionContainerType"/>
<xs:element name="keyValueCollection" type="keyValueCollectionContainerType"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="instanceContainerType">
<xs:sequence>
<xs:element name="loader" type="instanceLoaderType"/>
<xs:element name="instance" type="nestedContainerType"/>
<xs:element name="collection" type="nestedContainerType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="class" type="xs:string"/>
<xs:attribute name="view" type="xs:string"/>
</xs:complexType>
<xs:complexType name="collectionContainerType">
<xs:sequence>
<xs:element name="loader" type="collectionLoaderType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="class" type="xs:string"/>
<xs:attribute name="view" type="xs:string"/>
</xs:complexType>
<xs:complexType name="nestedContainerType">
<xs:sequence>
<xs:element name="instance" type="nestedContainerType"/>
<xs:element name="collection" type="nestedContainerType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="property" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="instanceLoaderType">
<xs:sequence>
<xs:element name="query" type="queryType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="softDeletion" type="xs:boolean"/>
<xs:attribute name="dynamicAttributes" type="xs:boolean"/>
<xs:attribute name="entityId" type="xs:string"/>
</xs:complexType>
<xs:complexType name="collectionLoaderType">
<xs:sequence>
<xs:element name="query" type="queryType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="softDeletion" type="xs:boolean"/>
<xs:attribute name="dynamicAttributes" type="xs:boolean"/>
<xs:attribute name="firstResult" type="xs:integer"/>
<xs:attribute name="maxResults" type="xs:integer"/>
<xs:attribute name="cacheable" type="xs:boolean"/>
</xs:complexType>
<xs:complexType name="keyValueCollectionContainerType">
<xs:sequence>
<xs:element name="properties" type="keyValueCollectionContainerProperties"/>
<xs:element name="loader" type="keyValueCollectionLoaderType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="keyValueCollectionLoaderType">
<xs:sequence>
<xs:element name="query" type="queryType"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
<xs:attribute name="softDeletion" type="xs:boolean"/>
<xs:attribute name="firstResult" type="xs:integer"/>
<xs:attribute name="maxResults" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="keyValueCollectionContainerProperties">
<xs:sequence>
<xs:element name="property" maxOccurs="unbounded">
<xs:complexType mixed="true">
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="datatype" type="xs:string"/>
<xs:attribute name="class" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="idProperty" type="xs:string"/>
</xs:complexType>
<xs:complexType name="queryType">
<xs:sequence>
<xs:element name="condition" type="conditionType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="conditionType">
<!-- todo -->
</xs:complexType>
</xs:schema>

View File

@ -18,15 +18,19 @@
<xs:schema targetNamespace="http://schemas.haulmont.com/cuba/screen/fragment.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.haulmont.com/cuba/screen/fragment.xsd"
xmlns:data="http://schemas.haulmont.com/cuba/screen/data.xsd"
xmlns:layout="http://schemas.haulmont.com/cuba/screen/layout.xsd"
elementFormDefault="qualified">
<xs:include schemaLocation="http://schemas.haulmont.com/cuba/screen/data.xsd"/>
<xs:include schemaLocation="http://schemas.haulmont.com/cuba/screen/layout.xsd"/>
<!-- Window -->
<xs:element name="fragment">
<xs:complexType>
<xs:sequence>
<xs:element name="data" type="data:screenData"/>
<xs:element name="actions" minOccurs="0">
<xs:complexType>
<xs:sequence>

View File

@ -900,6 +900,11 @@
<xs:attribute name="property" type="xs:string"/>
</xs:attributeGroup>
<xs:attributeGroup name="hasDataContainer">
<xs:attribute name="dataContainer" type="xs:string"/>
<xs:attribute name="property" type="xs:string"/>
</xs:attributeGroup>
<xs:attributeGroup name="requiresDatasource">
<xs:attribute name="datasource" type="xs:string" use="required"/>
</xs:attributeGroup>
@ -941,6 +946,7 @@
<xs:attributeGroup name="hasOptions">
<xs:attribute name="optionsDatasource" type="xs:string"/>
<xs:attribute name="optionsContainer" type="xs:string"/>
</xs:attributeGroup>
<xs:attributeGroup name="hasCaptionSource">
@ -1050,7 +1056,15 @@
</xs:complexType>
<xs:complexType name="tableRowsType">
<xs:attribute name="datasource" type="xs:string" use="required"/>
<xs:attribute name="datasource" type="xs:string"/>
<xs:attribute name="dataContainer" type="xs:string"/>
<xs:attribute name="rowHeaderMode" type="rowHeaderMode"/>
</xs:complexType>
<xs:complexType name="treeTableRowsType">
<xs:attribute name="datasource" type="xs:string"/>
<xs:attribute name="dataContainer" type="xs:string"/>
<xs:attribute name="hierarchyProperty" type="xs:string"/>
<xs:attribute name="rowHeaderMode" type="rowHeaderMode"/>
</xs:complexType>
@ -1231,6 +1245,7 @@
<xs:attributeGroup ref="hasEditable"/>
<xs:attributeGroup ref="hasRequirements"/>
<xs:attributeGroup ref="hasDatasource"/>
<xs:attributeGroup ref="hasDataContainer"/>
<xs:attributeGroup ref="hasContextHelp"/>
</xs:extension>
</xs:complexContent>
@ -2046,6 +2061,27 @@
</xs:complexContent>
</xs:complexType>
<!-- TreeTable -->
<xs:complexType name="treeTableComponent">
<xs:complexContent>
<xs:extension base="baseComponent">
<xs:all>
<xs:element name="actions" minOccurs="0" type="componentActions"/>
<xs:element name="buttonsPanel" minOccurs="0" type="buttonsPanelComponent"/>
<xs:element name="rowsCount" minOccurs="0">
<xs:complexType/>
</xs:element>
<xs:element name="columns" type="tableColumnsList"/>
<xs:element name="rows" type="treeTableRowsType"/>
</xs:all>
<xs:attribute name="stylename" type="tableStylename"/>
<xs:attributeGroup ref="isTableComponent"/>
<xs:attributeGroup ref="hasContextHelp"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- GroupTable -->
<xs:complexType name="groupTableComponent">
<xs:complexContent>
@ -2108,6 +2144,7 @@
<xs:attribute name="columnResizeMode" type="dataGridColumnResizeMode"/>
<xs:attribute name="contextMenuEnabled" type="xs:boolean"/>
<xs:attribute name="datasource" type="xs:string"/>
<xs:attribute name="dataContainer" type="xs:string"/>
<xs:attribute name="frozenColumnCount" type="xs:integer"/>
<xs:attribute name="headerVisible" type="xs:boolean"/>
<xs:attribute name="footerVisible" type="xs:boolean"/>
@ -2133,7 +2170,9 @@
<!-- TreeDataGrid -->
<xs:complexType name="treeDataGridComponent">
<xs:complexContent>
<xs:extension base="dataGridComponent"/>
<xs:extension base="dataGridComponent">
<xs:attribute name="hierarchyProperty" type="xs:string"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@ -2902,7 +2941,7 @@
<xs:element name="tree" type="treeComponent"/>
<xs:element name="table" type="tableComponent"/>
<xs:element name="treeTable" type="tableComponent"/>
<xs:element name="treeTable" type="treeTableComponent"/>
<xs:element name="groupTable" type="groupTableComponent"/>
<xs:element name="dataGrid" type="dataGridComponent"/>
<xs:element name="treeDataGrid" type="treeDataGridComponent"/>

View File

@ -18,15 +18,19 @@
<xs:schema targetNamespace="http://schemas.haulmont.com/cuba/screen/window.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
xmlns:data="http://schemas.haulmont.com/cuba/screen/data.xsd"
xmlns:layout="http://schemas.haulmont.com/cuba/screen/layout.xsd"
elementFormDefault="qualified">
<xs:include schemaLocation="http://schemas.haulmont.com/cuba/screen/data.xsd"/>
<xs:include schemaLocation="http://schemas.haulmont.com/cuba/screen/layout.xsd"/>
<!-- Window -->
<xs:element name="window">
<xs:complexType>
<xs:sequence>
<xs:element name="data" type="data:screenData"/>
<xs:element name="timers" minOccurs="0" type="layout:timer"/>
<xs:element name="actions" minOccurs="0">
<xs:complexType>

View File

@ -129,7 +129,7 @@ public abstract class AbstractDataGridLoader<T extends DataGrid> extends Actions
DataLoader dataLoader = null;
Datasource datasource = null;
String containerId = element.attributeValue("container");
String containerId = element.attributeValue("dataContainer");
if (containerId != null) {
FrameOwner frameOwner = context.getFrame().getFrameOwner();
ScreenData screenData = UiControllerUtils.getScreenData(frameOwner);

View File

@ -65,7 +65,7 @@ public abstract class AbstractFieldLoader<T extends Field> extends AbstractDatas
@SuppressWarnings("unchecked")
protected void loadContainer(T component, Element element) {
String containerId = element.attributeValue("container");
String containerId = element.attributeValue("dataContainer");
if (containerId != null) {
FrameOwner frameOwner = context.getFrame().getFrameOwner();
ScreenData screenData = UiControllerUtils.getScreenData(frameOwner);

View File

@ -127,7 +127,7 @@ public abstract class AbstractTableLoader<T extends Table> extends ActionsHolder
DataLoader dataLoader = null;
Datasource datasource = null;
String containerId = rowsElement.attributeValue("container");
String containerId = rowsElement.attributeValue("dataContainer");
if (containerId != null) {
FrameOwner frameOwner = context.getFrame().getFrameOwner();
ScreenData screenData = UiControllerUtils.getScreenData(frameOwner);

View File

@ -18,8 +18,8 @@ package com.haulmont.cuba.web.gui.components;
import com.haulmont.bali.events.Subscription;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.Messages;
import com.haulmont.cuba.core.entity.KeyValueEntity;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.data.DataGridSource;
import com.haulmont.cuba.gui.components.data.TableSource;
@ -35,9 +35,13 @@ import com.haulmont.cuba.gui.model.*;
import com.haulmont.cuba.web.gui.icons.IconResolver;
import com.haulmont.cuba.web.widgets.CubaRowsCount;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@ -71,6 +75,8 @@ public class WebRowsCount extends WebAbstractComponent<CubaRowsCount> implements
private RowsCountTarget target;
private static final Logger log = LoggerFactory.getLogger(WebRowsCount.class);
public WebRowsCount() {
component = new CubaRowsCount();
component.setStyleName(TABLE_ROWS_COUNT_STYLENAME);
@ -164,10 +170,13 @@ public class WebRowsCount extends WebAbstractComponent<CubaRowsCount> implements
if (container instanceof HasLoader) {
loader = ((HasLoader) container).getLoader();
}
if (!(loader instanceof CollectionLoader)) {
throw new IllegalStateException(String.format("Invalid loader for container %s: %s", container, loader));
if (loader == null) {
throw new IllegalStateException(String.format("Loader for container %s not found", container));
}
return new LoaderAdapter((CollectionLoader) loader);
if (!(loader instanceof BaseCollectionLoader)) {
throw new IllegalStateException("RowsCount component currently supports only BaseCollectionLoader");
}
return new LoaderAdapter((BaseCollectionLoader) loader);
}
protected Adapter createDatasourceAdapter(CollectionDatasource datasource) {
@ -436,10 +445,10 @@ public class WebRowsCount extends WebAbstractComponent<CubaRowsCount> implements
protected class LoaderAdapter implements Adapter {
private CollectionContainer container;
private CollectionLoader loader;
private BaseCollectionLoader loader;
@SuppressWarnings("unchecked")
public LoaderAdapter(CollectionLoader loader) {
public LoaderAdapter(BaseCollectionLoader loader) {
this.loader = loader;
container = loader.getContainer();
@ -482,7 +491,22 @@ public class WebRowsCount extends WebAbstractComponent<CubaRowsCount> implements
@SuppressWarnings("unchecked")
@Override
public int getCount() {
return (int) dataManager.getCount(loader.createLoadContext());
if (loader instanceof CollectionLoader) {
return (int) dataManager.getCount(((CollectionLoader) loader).createLoadContext());
} else if (loader instanceof KeyValueCollectionLoader) {
ValueLoadContext context = ((KeyValueCollectionLoader) loader).createLoadContext();
QueryTransformer transformer = QueryTransformerFactory.createTransformer(context.getQuery().getQueryString());
// TODO it doesn't work for query containing scalars in select
transformer.replaceWithCount();
context.getQuery().setQueryString(transformer.getResult());
context.setProperties(Collections.singletonList("cnt"));
List<KeyValueEntity> list = dataManager.loadValues(context);
Number count = list.get(0).getValue("cnt");
return count == null ? 0 : count.intValue();
} else {
log.warn("Unsupported loader type: " + loader.getClass().getName());
return 0;
}
}
@Override

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2008-2018 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.web.tmp;
import com.haulmont.cuba.gui.screen.Screen;
import com.haulmont.cuba.gui.screen.Subscribe;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
@UiController("tmpUserInfoBrowse")
@UiDescriptor("tmp-user-info-browse.xml")
public class TmpUserInfoBrowse extends Screen {
@Subscribe
protected void beforeShow(BeforeShowEvent event) {
getScreenData().loadAll();
}
}

View File

@ -14,7 +14,7 @@
~ limitations under the License.
-->
<window
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
class="com.haulmont.cuba.web.tmp.DcScreen4"
caption="Screen 4"
messagesPack="com.haulmont.cuba.web.tmp">
@ -28,7 +28,7 @@
cacheable="false" softDeletion="true">
<query>
select u from sec$User u
where u.group = :groupId
where u.group.id = :groupId
order by u.name
<condition>
<and>

View File

@ -14,7 +14,8 @@
~ limitations under the License.
-->
<window caption="User Browser">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="User Browser">
<data>
<collection id="usersCont"
@ -46,7 +47,7 @@
<column id="group"/>
<column id="active"/>
</columns>
<rows container="usersCont"/>
<rows dataContainer="usersCont"/>
</groupTable>
</layout>
</window>

View File

@ -14,7 +14,8 @@
~ limitations under the License.
-->
<window caption="User Editor">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="User Editor">
<data>
<instance id="userCont" class="com.haulmont.cuba.security.entity.User" view="user.edit">
@ -25,8 +26,8 @@
</data>
<layout spacing="true" expand="userRolesTable">
<textField id="loginField" container="userCont" property="login"/>
<textField id="nameField" container="userCont" property="name"/>
<textField id="loginField" dataContainer="userCont" property="login"/>
<textField id="nameField" dataContainer="userCont" property="name"/>
<table id="userRolesTable"
width="100%">
<buttonsPanel>
@ -38,7 +39,7 @@
<column id="role.name"/>
<column id="role.locName"/>
</columns>
<rows container="userRolesCont"/>
<rows dataContainer="userRolesCont"/>
</table>
<hbox spacing="true">
<button id="okBtn" caption="OK"/>

View File

@ -14,11 +14,12 @@
~ limitations under the License.
-->
<window caption="Groups">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="Groups">
<data>
<collection id="groupsCont" class="com.haulmont.cuba.security.entity.Group" view="group.browse">
<loader id="groupsLoader">
<loader id="groupsLoader" maxResults="www">
<query>select g from sec$Group g order by g.name</query>
</loader>
</collection>
@ -31,7 +32,7 @@
<column id="id"/>
<column id="version"/>
</columns>
<rows container="groupsCont" hierarchyProperty="parent"/>
<rows dataContainer="groupsCont" hierarchyProperty="parent"/>
</treeTable>
</layout>
</window>

View File

@ -14,7 +14,8 @@
~ limitations under the License.
-->
<window caption="Groups">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="Groups">
<data>
<collection id="groupsCont" class="com.haulmont.cuba.security.entity.Group" view="group.browse">
@ -26,7 +27,7 @@
<layout spacing="true" expand="groupsTree">
<treeDataGrid id="groupsTree" width="100%" multiselect="true"
container="groupsCont" hierarchyProperty="parent">
dataContainer="groupsCont" hierarchyProperty="parent">
<columns>
<column property="name"/>
<column property="id"/>

View File

@ -14,13 +14,14 @@
~ limitations under the License.
-->
<window caption="User Browser">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="User Browser">
<data>
<collection id="usersCont"
class="com.haulmont.cuba.security.entity.User" view="user.browse">
<loader id="usersLoader">
<loader id="usersLoader" dynamicAttributes="true">
<query>
select u from sec$User u
order by u.name
@ -33,7 +34,7 @@
<filter id="usersFilter"
dataLoader="usersLoader"/>
<dataGrid id="usersGrid"
container="usersCont"
dataContainer="usersCont"
width="100%">
<buttonsPanel>
<button id="createBtn" caption="Create"/>

View File

@ -0,0 +1,49 @@
<!--
~ Copyright (c) 2008-2018 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.
-->
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="User Info Browser">
<data>
<keyValueCollection id="userInfoCont">
<properties>
<property name="login"/>
<property name="name"/>
</properties>
<loader id="userInfoLoader">
<query>
select u.login, u.name from sec$User u
order by u.login
</query>
</loader>
</keyValueCollection>
</data>
<layout spacing="true" expand="userInfoGrid">
<dataGrid id="userInfoGrid"
dataContainer="userInfoCont"
width="100%">
<buttonsPanel>
<button id="createBtn" caption="Create"/>
</buttonsPanel>
<!--<rowsCount/>-->
<columns>
<column property="login"/>
<column property="name"/>
</columns>
</dataGrid>
</layout>
</window>

View File

@ -14,11 +14,12 @@
~ limitations under the License.
-->
<window caption="User Role">
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="User Role">
<data>
<instance id="userRoleCont" class="com.haulmont.cuba.security.entity.UserRole" view="tmp.user.edit">
<loader id="userRoleLoader"/>
<loader id="userRoleLoader" dynamicAttributes="true"/>
</instance>
<collection id="rolesCont" class="com.haulmont.cuba.security.entity.Role" view="_minimal">
@ -32,8 +33,8 @@
</data>
<layout spacing="true" expand="spacer">
<textField id="userField" container="userRoleCont" property="user.login"/>
<lookupField id="roleField" container="userRoleCont" property="role" optionsContainer="rolesCont"/>
<textField id="userField" dataContainer="userRoleCont" property="user.login"/>
<lookupField id="roleField" dataContainer="userRoleCont" property="role" optionsContainer="rolesCont"/>
<hbox spacing="true">
<button id="okBtn" caption="OK"/>
<button id="cancelBtn" caption="Cancel"/>

View File

@ -30,6 +30,7 @@
<item id="tmpGroupBrowse"/>
<item id="tmpUserDataGrid"/>
<item id="tmpGroupTreeDataGrid"/>
<item id="tmpUserInfoBrowse"/>
<separator/>
<item id="sec$User.browse"/>
<item id="sec$Group.browse"/>

View File

@ -22,16 +22,13 @@ import com.haulmont.cuba.gui.model.*
import com.haulmont.cuba.gui.model.impl.ScreenDataXmlLoader
import com.haulmont.cuba.gui.model.impl.StandardCollectionLoader
import com.haulmont.cuba.gui.model.impl.StandardInstanceLoader
import com.haulmont.cuba.security.entity.Permission
import com.haulmont.cuba.security.entity.User
import com.haulmont.cuba.security.entity.UserRole
import com.haulmont.cuba.web.testmodel.sales.Order
import com.haulmont.cuba.web.testmodel.sales.OrderLine
import com.haulmont.cuba.web.testmodel.sales.Product
import com.haulmont.cuba.web.testmodel.sales.ProductTag
import org.dom4j.Document
import spec.cuba.web.WebSpec
import spock.lang.Ignore
class ScreenDataTest extends WebSpec {
@ -91,6 +88,18 @@ class ScreenDataTest extends WebSpec {
</query>
</loader>
</collection>
<keyValueCollection id="userInfoCont">
<properties>
<property name="login"/>
<property name="name"/>
</properties>
<loader id="userInfoLoader">
<query>
select u.login, u.name from sec$User u where u.id = 1
</query>
</loader>
</keyValueCollection>
</data>
'''
Document document = Dom4j.readDocument(xml)
@ -105,6 +114,8 @@ class ScreenDataTest extends WebSpec {
InstanceLoader<User> userLoader = screenData.getLoader('userLoader')
CollectionContainer<User> usersCont = screenData.getContainer('usersCont')
CollectionLoader<User> usersLoader = screenData.getLoader('usersLoader')
KeyValueCollectionContainer userInfoCont = screenData.getContainer('userInfoCont')
KeyValueCollectionLoader userInfoLoader = screenData.getLoader('userInfoLoader')
then:
@ -124,6 +135,11 @@ class ScreenDataTest extends WebSpec {
usersLoader.firstResult == 0
usersLoader.maxResults == Integer.MAX_VALUE
!usersLoader.cacheable
userInfoCont.getEntityMetaClass().getProperty('login') != null
userInfoCont.getEntityMetaClass().getProperty('name') != null
userInfoLoader.getContainer() == userInfoCont
userInfoLoader.getQuery() == 'select u.login, u.name from sec$User u where u.id = 1'
}
def "loader options"() {
@ -132,18 +148,32 @@ class ScreenDataTest extends WebSpec {
<instance id="userCont"
class="com.haulmont.cuba.security.entity.User" view="user.edit">
<loader id="userLoader" entityId="60885987-1b61-4247-94c7-dff348347f93" softDeletion="false"/>
<loader id="userLoader" entityId="60885987-1b61-4247-94c7-dff348347f93" softDeletion="false"
dynamicAttributes="true"/>
</instance>
<collection id="usersCont"
class="com.haulmont.cuba.security.entity.User" view="user.browse">
<loader id="usersLoader" softDeletion="false" firstResult="100" maxResults="1000" cacheable="true">
<loader id="usersLoader" softDeletion="false" firstResult="100" maxResults="1000" cacheable="true"
dynamicAttributes="true">
<query>
select u from sec$User u
</query>
</loader>
</collection>
<keyValueCollection id="userInfoCont">
<properties>
<property name="login"/>
<property name="name"/>
</properties>
<loader id="userInfoLoader" store="foo" softDeletion="false" firstResult="100" maxResults="1000">
<query>
select u.login, u.name from sec$User u where u.id = 1
</query>
</loader>
</keyValueCollection>
</data>
'''
Document document = Dom4j.readDocument(xml)
@ -155,18 +185,26 @@ class ScreenDataTest extends WebSpec {
screenDataLoader.load(screenData, document.rootElement)
InstanceLoader<User> userLoader = screenData.getLoader('userLoader')
CollectionLoader<User> usersLoader = screenData.getLoader('usersLoader')
KeyValueCollectionLoader userInfoLoader = screenData.getLoader('userInfoLoader')
then:
userLoader.entityId == UUID.fromString('60885987-1b61-4247-94c7-dff348347f93')
!userLoader.softDeletion
userLoader.loadDynamicAttributes
((StandardInstanceLoader) userLoader).createLoadContext().view == cont.getBean(ViewRepository).getView(User, 'user.edit')
!usersLoader.softDeletion
usersLoader.firstResult == 100
usersLoader.maxResults == 1000
usersLoader.cacheable
usersLoader.loadDynamicAttributes
((StandardCollectionLoader) usersLoader).createLoadContext().view == cont.getBean(ViewRepository).getView(User, 'user.browse')
!userInfoLoader.softDeletion
userInfoLoader.firstResult == 100
userInfoLoader.maxResults == 1000
userInfoLoader.storeName == 'foo'
}
def "nested containers"() {