New presentation data layer #474

This commit is contained in:
Konstantin Krivopustov 2018-03-07 17:59:46 +04:00 committed by Yuriy Artamonov
parent 86241d282f
commit 379cf5462f
47 changed files with 4045 additions and 37 deletions

View File

@ -1090,6 +1090,9 @@ def generateClassDirs(Collection projects) {
}
}
zipProject {
excludeFromZip = ['out']
}
task aggregateJavadoc(type: Javadoc,
description: 'Generate javadocs from all child projects as if it was a single project',

View File

@ -27,6 +27,8 @@ import com.haulmont.cuba.core.sys.FormatStringsRegistryImpl;
import mockit.Mocked;
import mockit.Expectations;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
@ -92,10 +94,14 @@ public class CubaClientTestCase {
protected TestBeanValidation beanValidation;
protected TestEntityStates entityStates;
protected ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
protected MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
public CubaClientTestCase() {
private Logger log = LoggerFactory.getLogger(CubaClientTestCase.class);
static {
String property = System.getProperty("logback.configurationFile");
if (StringUtils.isBlank(property)) {
System.setProperty("logback.configurationFile", "test-logback.xml");
@ -107,6 +113,8 @@ public class CubaClientTestCase {
* @param packageName package FQN, e.g. <code>com.haulmont.cuba.core.entity</code>
*/
protected void addEntityPackage(String packageName) {
log.debug("Adding entity package: " + packageName);
String packagePrefix = packageName.replace(".", "/") + "/**/*.class";
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packagePrefix;
Resource[] resources;
@ -156,6 +164,7 @@ public class CubaClientTestCase {
* once in their @Before method.
*/
protected void setupInfrastructure() {
log.debug("Setting up infrastructure");
new Expectations() {
{
AppContext.getProperty("cuba.confDir"); result = System.getProperty("user.dir"); minTimes = 0;
@ -184,6 +193,8 @@ public class CubaClientTestCase {
beanValidation = new TestBeanValidation();
entityStates = new TestEntityStates();
((TestMetadataTools) metadata.getTools()).setMessages(messages);
((TestMetadataTools) metadata.getTools()).setUserSessionSource(userSessionSource);
@ -243,9 +254,13 @@ public class CubaClientTestCase {
AppBeans.get(MessageTools.class); result = messageTools; minTimes = 0;
AppBeans.get(MessageTools.NAME, MessageTools.class); result = messageTools; minTimes = 0;
AppBeans.get(BeanValidation.NAME); result = beanValidation; minTimes = 0;
AppBeans.get(BeanValidation.class); result = beanValidation; minTimes = 0;
AppBeans.get(BeanValidation.NAME, BeanValidation.class); result = beanValidation; minTimes = 0;
AppBeans.get(BeanValidation.NAME); result = beanValidation;
AppBeans.get(BeanValidation.class); result = beanValidation;
AppBeans.get(BeanValidation.NAME, BeanValidation.class); result = beanValidation;
AppBeans.get(EntityStates.NAME); result = entityStates;
AppBeans.get(EntityStates.class); result = entityStates;
AppBeans.get(EntityStates.NAME, BeanValidation.class); result = entityStates;
}
};

View File

@ -48,8 +48,6 @@
<logger name="eclipselink.sql" level="DEBUG"/>
<logger name="org.springframework" level="WARN"/>
<logger name="org.activiti" level="INFO"/>
<logger name="freemarker" level="INFO"/>

View File

@ -0,0 +1,34 @@
/*
* 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.client.testsupport;
import com.haulmont.cuba.core.global.EntityStates;
/**
*
*/
public class TestEntityStates extends EntityStates {
@Override
public boolean isLoaded(Object entity, String property) {
return true;
}
@Override
public void checkLoaded(Object entity, String... properties) {
}
}

View File

@ -28,12 +28,14 @@ import com.haulmont.cuba.core.global.BeanValidation;
import com.haulmont.cuba.core.global.MessageTools;
import com.haulmont.cuba.core.global.MetadataTools;
import com.haulmont.cuba.gui.components.Field;
import com.haulmont.cuba.gui.components.PropertyBoundComponent;
import com.haulmont.cuba.gui.components.RequiredValueMissingException;
import com.haulmont.cuba.gui.components.ValidationException;
import com.haulmont.cuba.gui.components.compatibility.ComponentValueListenerWrapper;
import com.haulmont.cuba.gui.components.validators.BeanValidator;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.data.ValueListener;
import com.haulmont.cuba.gui.model.InstanceContainer;
import org.apache.commons.lang.StringUtils;
import javax.swing.*;
@ -44,8 +46,8 @@ import java.util.*;
import java.util.List;
import java.util.function.Consumer;
public abstract class DesktopAbstractField<C extends JComponent> extends DesktopAbstractComponent<C>
implements Field, DesktopComponent.HasContextHelpClickHandler {
public abstract class DesktopAbstractField<C extends JComponent> extends DesktopAbstractComponent<C> implements Field,
DesktopComponent.HasContextHelpClickHandler, PropertyBoundComponent {
protected List<ValueChangeListener> listeners = new ArrayList<>();
@ -358,4 +360,14 @@ public abstract class DesktopAbstractField<C extends JComponent> extends Desktop
contextHelpIconClickHandler.accept(event);
}
}
@Override
public InstanceContainer getEntityContainer() {
throw new UnsupportedOperationException();
}
@Override
public void setContainer(InstanceContainer container, String property) {
throw new UnsupportedOperationException();
}
}

View File

@ -45,6 +45,7 @@ import com.haulmont.cuba.gui.data.impl.CollectionDsActionsNotifier;
import com.haulmont.cuba.gui.data.impl.DatasourceImplementation;
import com.haulmont.cuba.gui.data.impl.WeakCollectionChangeListener;
import com.haulmont.cuba.gui.data.impl.WeakItemPropertyChangeListener;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.presentations.Presentations;
import net.miginfocom.layout.CC;
import net.miginfocom.swing.MigLayout;
@ -806,6 +807,11 @@ public abstract class DesktopAbstractTable<C extends JXTable, E extends Entity>
setSortable(false);
}
@Override
public void setContainer(CollectionContainer container) {
throw new UnsupportedOperationException();
}
protected boolean canBeSorted(CollectionDatasource datasource) {
//noinspection SimplifiableConditionalExpression
return datasource instanceof PropertyDatasource ?

View File

@ -0,0 +1,31 @@
/*
* 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.bali.util;
/**
*
*/
public class Numbers {
public static int nullToZero(Integer value) {
return value == null ? 0 : value;
}
public static long nullToZero(Long value) {
return value == null ? 0 : value;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.MetaPropertyPath;
import com.haulmont.cuba.gui.model.InstanceContainer;
/**
*
*/
public interface PropertyBoundComponent {
InstanceContainer getEntityContainer();
MetaPropertyPath getMetaPropertyPath();
void setContainer(InstanceContainer container, String property);
}

View File

@ -22,6 +22,7 @@ import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.model.CollectionContainer;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -56,6 +57,8 @@ public interface Table<E extends Entity>
void setDatasource(CollectionDatasource datasource);
void setContainer(CollectionContainer container);
void setRequired(Column column, boolean required, String message);
void addValidator(Column column, com.haulmont.cuba.gui.components.Field.Validator validator);

View File

@ -19,7 +19,7 @@ package com.haulmont.cuba.gui.components;
import java.util.EventObject;
public interface TextInputField extends Field, Component.Buffered, Component.Focusable {
public interface TextInputField extends Field, Component.Buffered, Component.Focusable, PropertyBoundComponent {
/**
* Defines case conversion for text input fields,

View File

@ -0,0 +1,72 @@
/*
* 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.model;
import com.haulmont.cuba.core.entity.Entity;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Comparator;
import java.util.EventObject;
import java.util.List;
import java.util.function.Predicate;
/**
*
*/
public interface CollectionContainer<T extends Entity> extends InstanceContainer<T> {
List<T> getItems();
List<T> getMutableItems();
void setItems(@Nullable Collection<T> entities);
@Nullable
T getItem(Object entityId);
/**
*
*/
class CollectionChangeEvent<T extends Entity> extends EventObject {
public CollectionChangeEvent(CollectionContainer<T> container) {
super(container);
}
@SuppressWarnings("unchecked")
@Override
public CollectionContainer<T> getSource() {
return (CollectionContainer) super.getSource();
}
}
/**
*
*/
@FunctionalInterface
interface CollectionChangeListener<T extends Entity> {
/**
* Enclosed collection changed.
*/
void collectionChanged(CollectionChangeEvent<T> e);
}
void addCollectionChangeListener(CollectionChangeListener<T> listener);
void removeCollectionChangeListener(CollectionChangeListener<T> listener);
}

View File

@ -0,0 +1,52 @@
/*
* 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.model;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.View;
/**
*
*/
public interface CollectionLoader<T extends Entity> extends DataLoader {
CollectionContainer<T> getContainer();
void setContainer(CollectionContainer<T> container);
String getQuery();
void setQuery(String query);
int getMaxResults();
void setMaxResults(int maxResults);
boolean isSoftDeletion();
void setSoftDeletion(boolean softDeletion);
boolean isCacheable();
void setCacheable(boolean cacheable);
View getView();
void setView(View view);
void setView(String viewName);
}

View File

@ -0,0 +1,118 @@
/*
* 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.model;
import com.haulmont.cuba.core.entity.Entity;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.EventObject;
/**
*
*/
public interface DataContext {
@Nullable
<T extends Entity<K>, K> T find(Class<T> entityClass, K entityId);
boolean contains(@Nullable Entity entity);
<T extends Entity> T merge(T entity);
<T extends Entity> T merge(T entity, boolean deep);
void remove(Entity entity);
void evict(Entity entity);
boolean hasChanges();
void commit();
DataContext getParent();
void setParent(DataContext parentContext);
class PreCommitEvent extends EventObject {
private final Collection<Entity> modifiedInstances;
private final Collection<Entity> removedInstances;
private boolean commitPrevented;
public PreCommitEvent(DataContext dataContext, Collection<Entity> modified, Collection<Entity> removed) {
super(dataContext);
this.modifiedInstances = modified;
this.removedInstances = removed;
}
@Override
public DataContext getSource() {
return (DataContext) super.getSource();
}
public Collection<Entity> getModifiedInstances() {
return modifiedInstances;
}
public Collection<Entity> getRemovedInstances() {
return removedInstances;
}
public void preventCommit() {
commitPrevented = true;
}
public boolean isCommitPrevented() {
return commitPrevented;
}
}
@FunctionalInterface
interface PreCommitListener {
void preCommit(PreCommitEvent e);
}
void addPreCommitListener(PreCommitListener listener);
void removePreCommitListener(PreCommitListener listener);
class PostCommitEvent extends EventObject {
private final Collection<Entity> committedInstances;
public PostCommitEvent(DataContext dataContext, Collection<Entity> committedInstances) {
super(dataContext);
this.committedInstances = committedInstances;
}
@Override
public DataContext getSource() {
return (DataContext) super.getSource();
}
public Collection<Entity> getCommittedInstances() {
return committedInstances;
}
}
@FunctionalInterface
interface PostCommitListener {
void postCommit(PostCommitEvent e);
}
void addPostCommitListener(PostCommitListener listener);
void removePostCommitListener(PostCommitListener listener);
}

View File

@ -0,0 +1,62 @@
/*
* 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.model;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.EntityStates;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.model.impl.*;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
/**
*
*/
@Component("cuba_DataContextFactory")
public class DataContextFactory {
@Inject
protected Metadata metadata;
@Inject
protected DataManager dataManager;
@Inject
protected EntityStates entityStates;
public DataContext createDataContext() {
return new StandardDataContext(metadata, dataManager, entityStates);
}
public <T extends Entity> InstanceContainer<T> createInstanceContainer(Class<T> entityClass) {
return new InstanceContainerImpl<>(metadata.getClassNN(entityClass));
}
public <T extends Entity> CollectionContainer<T> createCollectionContainer(Class<T> entityClass) {
return new CollectionContainerImpl<>(metadata.getClassNN(entityClass));
}
public <T extends Entity<K>, K> InstanceLoader<T, K> createInstanceLoader() {
return new StandardInstanceLoader<>(metadata, dataManager);
}
public <T extends Entity> CollectionLoader<T> createCollectionLoader() {
return new StandardCollectionLoader<>(metadata, dataManager);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.model;
import javax.annotation.Nullable;
/**
*
*/
public interface DataLoader {
@Nullable
DataContext getDataContext();
void setDataContext(DataContext dataContext);
void load();
}

View File

@ -0,0 +1,156 @@
/*
* 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.model;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.entity.Entity;
import javax.annotation.Nullable;
import java.util.EventObject;
/**
*
*/
public interface InstanceContainer<T extends Entity> {
@Nullable
T getItem();
T getItemNN();
void setItem(T entity);
MetaClass getMetaClass();
class ItemPropertyChangeEvent<T extends Entity> extends EventObject {
private final T item;
private final String property;
private final Object prevValue;
private final Object value;
public ItemPropertyChangeEvent(InstanceContainer<T> container, T item, String property, Object prevValue, Object value) {
super(container);
this.item = item;
this.property = property;
this.prevValue = prevValue;
this.value = value;
}
@SuppressWarnings("unchecked")
@Override
public InstanceContainer<T> getSource() {
return (InstanceContainer) super.getSource();
}
/**
* @return item, which property value is changed
*/
public T getItem() {
return item;
}
/**
* @return property name
*/
public String getProperty() {
return property;
}
/**
* @return previous value of item property
*/
@Nullable
public Object getPrevValue() {
return prevValue;
}
/**
* @return current value of item property
*/
@Nullable
public Object getValue() {
return value;
}
}
/**
* Listener to datasource item property value change events.
*/
@FunctionalInterface
interface ItemPropertyChangeListener<T extends Entity> {
/**
* Property value of some datasource item changed. In case of {@link CollectionContainer} this method may be
* called for any item of collection if its property value changed.
*/
void itemPropertyChanged(ItemPropertyChangeEvent<T> e);
}
void addItemPropertyChangeListener(ItemPropertyChangeListener<T> listener);
void removeItemPropertyChangeListener(ItemPropertyChangeListener<T> listener);
/**
* Container item change event.
*/
class ItemChangeEvent<T extends Entity> extends EventObject {
private final T prevItem;
private final T item;
public ItemChangeEvent(InstanceContainer<T> container, T prevItem, T item) {
super(container);
this.prevItem = prevItem;
this.item = item;
}
@SuppressWarnings("unchecked")
@Override
public InstanceContainer<T> getSource() {
return (InstanceContainer) super.getSource();
}
/**
* @return current item
*/
@Nullable
public T getItem() {
return item;
}
/**
* @return previously selected item
*/
@Nullable
public T getPrevItem() {
return prevItem;
}
}
/**
* Listener to container item change events.
*/
@FunctionalInterface
interface ItemChangeListener<T extends Entity> {
/**
* Current item changed, that is now {@link InstanceContainer#getItem()} returns a different instance.
*/
void itemChanged(ItemChangeEvent<T> e);
}
void addItemChangeListener(ItemChangeListener<T> listener);
void removeItemChangeListener(ItemChangeListener<T> listener);
}

View File

@ -0,0 +1,44 @@
/*
* 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.model;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.View;
/**
*
*/
public interface InstanceLoader<T extends Entity<K>, K> extends DataLoader {
InstanceContainer<T> getContainer();
void setContainer(InstanceContainer<T> container);
K getEntityId();
void setEntityId(K entityId);
boolean isSoftDeletion();
void setSoftDeletion(boolean softDeletion);
View getView();
void setView(View view);
void setView(String viewName);
}

View File

@ -0,0 +1,102 @@
/*
* 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.model.impl;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.gui.model.CollectionContainer;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
*
*/
public class CollectionContainerImpl<T extends Entity> extends InstanceContainerImpl<T> implements CollectionContainer<T> {
protected List<T> collection = new ArrayList<>();
public CollectionContainerImpl(MetaClass metaClass) {
super(metaClass);
}
@Override
public List<T> getItems() {
return Collections.unmodifiableList(collection);
}
@Override
public List<T> getMutableItems() {
return new ObservableList<>(collection, this::fireCollectionChanged);
}
@Override
public void setItems(@Nullable Collection<T> entities) {
detachListener(collection);
collection.clear();
if (entities != null) {
collection.addAll(entities);
attachListener(collection);
}
fireCollectionChanged();
if (item != null && !collection.contains(item)) {
setItem(null);
}
}
@Nullable
@Override
public T getItem(Object entityId) {
return collection.stream()
.filter(entity -> entity.getId().equals(entityId))
.findAny()
.orElse(null);
}
@Override
public void addCollectionChangeListener(CollectionChangeListener<T> listener) {
getEventRouter().addListener(CollectionChangeListener.class, listener);
}
@Override
public void removeCollectionChangeListener(CollectionChangeListener<T> listener) {
getEventRouter().removeListener(CollectionChangeListener.class, listener);
}
protected void fireCollectionChanged() {
CollectionChangeEvent<T> collectionChangeEvent = new CollectionChangeEvent<>(this);
//noinspection unchecked
getEventRouter().fireEvent(CollectionChangeListener.class, CollectionChangeListener::collectionChanged, collectionChangeEvent);
}
protected void attachListener(Collection<T> entities) {
for (T entity : entities) {
attachListener(entity);
}
}
protected void detachListener(Collection<T> entities) {
for (T entity : entities) {
detachListener(entity);
}
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.model.impl;
import com.haulmont.bali.events.EventRouter;
import com.haulmont.bali.util.ParamsMap;
import com.haulmont.chile.core.model.Instance;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DevelopmentException;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.model.InstanceContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
/**
*
*/
public class InstanceContainerImpl<T extends Entity> implements InstanceContainer<T> {
private Logger log = LoggerFactory.getLogger(InstanceContainerImpl.class);
protected T item;
protected MetaClass metaClass;
protected EventRouter eventRouter;
protected boolean listenersEnabled = true;
protected Instance.PropertyChangeListener listener = new ItemListener();
public InstanceContainerImpl(MetaClass metaClass) {
this.metaClass = metaClass;
}
@Nullable
@Override
public T getItem() {
return item;
}
@Override
public T getItemNN() {
T item = getItem();
if (item == null)
throw new IllegalStateException("Item is null");
return item;
}
@Override
public void setItem(T item) {
T prevItem = this.item;
if (this.item != null) {
detachListener(this.item);
}
if (item != null) {
final MetaClass aClass = item.getMetaClass();
if (!aClass.equals(metaClass) && !metaClass.getDescendants().contains(aClass)) {
throw new DevelopmentException(String.format("Invalid item's metaClass '%s'", aClass),
ParamsMap.of("datasource", toString(), "metaClass", aClass));
}
attachListener(item);
}
this.item = item;
fireItemChanged(prevItem);
}
@Override
public MetaClass getMetaClass() {
return metaClass;
}
@Override
public void addItemPropertyChangeListener(ItemPropertyChangeListener<T> listener) {
getEventRouter().addListener(ItemPropertyChangeListener.class, listener);
}
@Override
public void removeItemPropertyChangeListener(ItemPropertyChangeListener<T> listener) {
getEventRouter().removeListener(ItemPropertyChangeListener.class, listener);
}
@Override
public void addItemChangeListener(ItemChangeListener<T> listener) {
getEventRouter().addListener(ItemChangeListener.class, listener);
}
@Override
public void removeItemChangeListener(ItemChangeListener<T> listener) {
getEventRouter().removeListener(ItemChangeListener.class, listener);
}
protected EventRouter getEventRouter() {
if (eventRouter == null) {
eventRouter = new EventRouter();
}
return eventRouter;
}
protected void fireItemChanged(T prevItem) {
ItemChangeEvent<T> itemChangeEvent = new ItemChangeEvent<>(this, prevItem, getItem());
//noinspection unchecked
getEventRouter().fireEvent(ItemChangeListener.class, ItemChangeListener::itemChanged, itemChangeEvent);
}
protected void attachListener(Instance entity) {
if (entity != null) {
entity.addPropertyChangeListener(listener);
}
}
protected void detachListener(Instance entity) {
if (entity != null) {
entity.removePropertyChangeListener(listener);
}
}
protected class ItemListener implements Instance.PropertyChangeListener {
@SuppressWarnings("unchecked")
@Override
public void propertyChanged(Instance.PropertyChangeEvent e) {
if (!listenersEnabled) {
return;
}
log.trace("propertyChanged: item={}, property={}, value={}, prevValue={}",
e.getItem(), e.getProperty(), e.getValue(), e.getPrevValue());
ItemPropertyChangeEvent<T> itemPropertyChangeEvent = new ItemPropertyChangeEvent<>(InstanceContainerImpl.this,
(T) e.getItem(), e.getProperty(), e.getPrevValue(), e.getValue());
getEventRouter().fireEvent(ItemPropertyChangeListener.class, ItemPropertyChangeListener::itemPropertyChanged,
itemPropertyChangeEvent);
}
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.model.impl;
import com.google.common.collect.ForwardingIterator;
import java.util.Iterator;
/**
*
*/
class ObservableIterator<T> extends ForwardingIterator<T> {
private Iterator<T> delegate;
private Runnable onCollectionChanged;
protected ObservableIterator(Iterator<T> delegate, Runnable onCollectionChanged) {
this.delegate = delegate;
this.onCollectionChanged = onCollectionChanged;
}
protected void fireCollectionChanged() {
if (onCollectionChanged != null)
onCollectionChanged.run();
}
@Override
protected Iterator<T> delegate() {
return delegate;
}
@Override
public void remove() {
super.remove();
fireCollectionChanged();
}
}

View File

@ -0,0 +1,148 @@
/*
* 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.model.impl;
import com.google.common.collect.ForwardingList;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
*
*/
@SuppressWarnings("NullableProblems")
public class ObservableList<T> extends ForwardingList<T> implements Serializable {
private List<T> delegate;
private Runnable onCollectionChanged;
public ObservableList(List<T> delegate, Runnable onCollectionChanged) {
this.delegate = delegate;
this.onCollectionChanged = onCollectionChanged;
}
private Object writeReplace() throws ObjectStreamException {
return delegate;
}
protected void fireCollectionChanged() {
if (onCollectionChanged != null)
onCollectionChanged.run();
}
@Override
protected List<T> delegate() {
return delegate;
}
@Override
public void add(int index, T element) {
super.add(index, element);
fireCollectionChanged();
}
@Override
public boolean add(T element) {
boolean changed = super.add(element);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean addAll(int index, Collection<? extends T> elements) {
boolean changed = super.addAll(index, elements);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean addAll(Collection<? extends T> collection) {
boolean changed = super.addAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public T set(int index, T element) {
T prev = super.set(index, element);
if (prev != element) {
fireCollectionChanged();
}
return prev;
}
@Override
public T remove(int index) {
T entity = super.remove(index);
fireCollectionChanged();
return entity;
}
@Override
public boolean remove(Object object) {
boolean changed = super.remove(object);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean removeAll(Collection<?> collection) {
boolean changed = super.removeAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean retainAll(Collection<?> collection) {
boolean changed = super.retainAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public void clear() {
boolean wasEmpty = isEmpty();
super.clear();
if (!wasEmpty)
fireCollectionChanged();
}
@Override
public ListIterator<T> listIterator() {
return new ObservableListIterator<>(super.listIterator(), onCollectionChanged);
}
@Override
public ListIterator<T> listIterator(int index) {
return new ObservableListIterator<>(super.listIterator(index), onCollectionChanged);
}
@Override
public Iterator<T> iterator() {
return new ObservableIterator<>(super.iterator(), onCollectionChanged);
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.model.impl;
import com.google.common.collect.ForwardingListIterator;
import java.util.ListIterator;
/**
*
*/
@SuppressWarnings("NullableProblems")
class ObservableListIterator<T> extends ForwardingListIterator<T> {
private ListIterator<T> delegate;
private Runnable onCollectionChanged;
protected ObservableListIterator(ListIterator<T> delegate, Runnable onCollectionChanged) {
this.delegate = delegate;
this.onCollectionChanged = onCollectionChanged;
}
protected void fireCollectionChanged() {
if (onCollectionChanged != null)
onCollectionChanged.run();
}
@Override
protected ListIterator<T> delegate() {
return delegate;
}
@Override
public void add(T element) {
super.add(element);
fireCollectionChanged();
}
@Override
public void set(T element) {
super.set(element);
fireCollectionChanged();
}
@Override
public void remove() {
super.remove();
fireCollectionChanged();
}
}

View File

@ -0,0 +1,106 @@
/*
* 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.model.impl;
import com.google.common.collect.ForwardingSet;
import java.io.ObjectStreamException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
*
*/
@SuppressWarnings("NullableProblems")
public class ObservableSet<T> extends ForwardingSet<T> {
private final Set<T> delegate;
private final Runnable onCollectionChanged;
public ObservableSet(Set<T> delegate, Runnable onCollectionChanged) {
this.delegate = delegate;
this.onCollectionChanged = onCollectionChanged;
}
private Object writeReplace() throws ObjectStreamException {
return delegate;
}
protected void fireCollectionChanged() {
if (onCollectionChanged != null)
onCollectionChanged.run();
}
@Override
protected Set<T> delegate() {
return delegate;
}
@Override
public boolean add(T element) {
boolean changed = super.add(element);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean removeAll(Collection<?> collection) {
boolean changed = super.removeAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean remove(Object object) {
boolean changed = super.remove(object);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean addAll(Collection<? extends T> collection) {
boolean changed = super.addAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public boolean retainAll(Collection<?> collection) {
boolean changed = super.retainAll(collection);
if (changed)
fireCollectionChanged();
return changed;
}
@Override
public void clear() {
boolean wasEmpty = isEmpty();
super.clear();
if (!wasEmpty)
fireCollectionChanged();
}
@Override
public Iterator<T> iterator() {
return new ObservableIterator<>(super.iterator(), onCollectionChanged);
}
}

View File

@ -0,0 +1,165 @@
/*
* 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.model.impl;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.model.DataContext;
import javax.annotation.Nullable;
import java.util.List;
/**
*
*/
public class StandardCollectionLoader<T extends Entity> implements CollectionLoader<T> {
private Metadata metadata;
private DataManager dataManager;
private DataContext dataContext;
private CollectionContainer<T> container;
private String query;
private int maxResults;
private boolean softDeletion;
private boolean cacheable;
private View view;
private String viewName;
public StandardCollectionLoader(Metadata metadata, DataManager dataManager) {
this.metadata = metadata;
this.dataManager = dataManager;
}
@Nullable
@Override
public DataContext getDataContext() {
return dataContext;
}
@Override
public void setDataContext(DataContext dataContext) {
this.dataContext = dataContext;
}
@Override
public void load() {
if (container == null)
throw new IllegalStateException("container is null");
if (query == null)
throw new IllegalStateException("query is null");
@SuppressWarnings("unchecked")
LoadContext<T> loadContext = LoadContext.create(container.getMetaClass().getJavaClass());
LoadContext.Query query = loadContext.setQueryString(this.query);
query.setCacheable(cacheable);
if (maxResults > 0)
query.setMaxResults(maxResults);
loadContext.setSoftDeletion(softDeletion);
if (view == null && viewName != null) {
this.view = metadata.getViewRepository().getView(container.getMetaClass(), viewName);
}
if (view != null) {
loadContext.setView(view);
}
List<T> list = dataManager.loadList(loadContext);
if (dataContext != null) {
for (T entity : list) {
dataContext.merge(entity);
}
}
container.setItems(list);
}
@Override
public CollectionContainer<T> getContainer() {
return container;
}
@Override
public void setContainer(CollectionContainer<T> container) {
this.container = container;
}
@Override
public String getQuery() {
return query;
}
@Override
public void setQuery(String query) {
this.query = query;
}
@Override
public int getMaxResults() {
return maxResults;
}
@Override
public void setMaxResults(int maxResults) {
this.maxResults = maxResults;
}
@Override
public boolean isSoftDeletion() {
return softDeletion;
}
@Override
public void setSoftDeletion(boolean softDeletion) {
this.softDeletion = softDeletion;
}
@Override
public boolean isCacheable() {
return cacheable;
}
@Override
public void setCacheable(boolean cacheable) {
this.cacheable = cacheable;
}
@Override
public View getView() {
return view;
}
@Override
public void setView(View view) {
this.view = view;
}
@Override
public void setView(String viewName) {
if (this.view != null)
throw new IllegalStateException("view is already set");
this.viewName = viewName;
}
}

View File

@ -0,0 +1,402 @@
/*
* 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.model.impl;
import com.haulmont.bali.events.EventRouter;
import com.haulmont.bali.util.Numbers;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.chile.core.model.Instance;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.impl.AbstractInstance;
import com.haulmont.cuba.core.entity.*;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.model.DataContext;
import javax.annotation.Nullable;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.util.*;
/**
*
*/
public class StandardDataContext implements DataContext {
protected final Metadata metadata;
protected final DataManager dataManager;
protected final EntityStates entityStates;
protected EventRouter eventRouter = new EventRouter();
protected Map<Class<?>, Map<Object, Entity>> content = new HashMap<>();
protected Set<Entity> modifiedInstances = new HashSet<>();
protected Set<Entity> removedInstances = new HashSet<>();
protected ChangeListener changeListener = new ChangeListener();
protected boolean disableListeners;
protected StandardDataContext parentContext;
public StandardDataContext(Metadata metadata, DataManager dataManager, EntityStates entityStates) {
this.metadata = metadata;
this.dataManager = dataManager;
this.entityStates = entityStates;
}
@Override
public DataContext getParent() {
return parentContext;
}
@Override
public void setParent(DataContext parentContext) {
Preconditions.checkNotNullArgument(parentContext, "parentContext is null");
if (!(parentContext instanceof StandardDataContext))
throw new IllegalArgumentException("Unsupported DataContext type: " + parentContext.getClass().getName());
this.parentContext = (StandardDataContext) parentContext;
for (Entity entity : this.parentContext.getAll()) {
Entity entityCopy;
try {
entityCopy = entity.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Cannot create a copy of " + entity, e);
}
copyState(entity, entityCopy);
merge(entityCopy);
}
}
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T extends Entity<K>, K> T find(Class<T> entityClass, K entityId) {
Map<Object, Entity> entityMap = content.get(entityClass);
if (entityMap != null)
return (T) entityMap.get(entityId);
return null;
}
@SuppressWarnings("unchecked")
@Override
public boolean contains(@Nullable Entity entity) {
if (entity == null)
return false;
else
return find(entity.getClass(), entity.getId()) != null;
}
@Override
public <T extends Entity> T merge(T entity) {
return merge(entity, true);
}
@SuppressWarnings("unchecked")
@Override
public <T extends Entity> T merge(T entity, boolean deep) {
Preconditions.checkNotNullArgument(entity, "entity is null");
disableListeners = true;
T result;
try {
result = (T) internalMerge(entity);
if (deep) {
metadata.getTools().traverseAttributes(entity, new MergingAttributeVisitor());
}
} finally {
disableListeners = false;
}
return result;
}
protected Entity internalMerge(Entity entity) {
Map<Object, Entity> entityMap = content.computeIfAbsent(entity.getClass(), aClass -> new HashMap<>());
Entity managedInstance = entityMap.get(entity.getId());
if (managedInstance != null) {
if (managedInstance != entity) {
copyState(entity, managedInstance);
}
return managedInstance;
}
entityMap.put(entity.getId(), entity);
entity.addPropertyChangeListener(changeListener);
if (entityStates.isNew(entity)) {
modifiedInstances.add(entity);
}
return entity;
}
/**
* (1) src.new -> dst.new : copy all non-null - should not happen (happens in setParent?)
* (2) src.new -> dst.det : do nothing - should not happen
* (3) src.det -> dst.new : copy all loaded, make detached - normal situation after commit
* (4) src.det -> dst.det : if src.version >= dst.version, copy all loaded - normal situation after commit (and in setParent?)
* if src.version < dst.version, do nothing - should not happen
*/
protected void copyState(Entity srcEntity, Entity dstEntity) {
boolean srcNew = entityStates.isNew(srcEntity);
boolean dstNew = entityStates.isNew(dstEntity);
if (srcNew && !dstNew) {
return;
}
if (!srcNew && !dstNew) {
if (srcEntity instanceof Versioned) {
int srcVer = Numbers.nullToZero(((Versioned) srcEntity).getVersion());
int dstVer = Numbers.nullToZero(((Versioned) dstEntity).getVersion());
if (srcVer < dstVer) {
return;
}
}
}
for (MetaProperty property : metadata.getClassNN(srcEntity.getClass()).getProperties()) {
String name = property.getName();
if ((!property.getRange().isClass() || property.getRange().getCardinality().isMany()) // local and collections
&& !property.isReadOnly() // read-write
&& (srcNew || entityStates.isLoaded(srcEntity, name))) { // loaded
AnnotatedElement annotatedElement = property.getAnnotatedElement();
if (annotatedElement instanceof Field) {
Field field = (Field) annotatedElement;
field.setAccessible(true);
try {
Object value = field.get(srcEntity);
if (srcNew || property.getRange().getCardinality().isMany()) {
if (value != null)
copyValue(dstEntity, field, value);
} else {
copyValue(dstEntity, field, value);
}
} catch (IllegalAccessException e) {
throw new RuntimeException("Error copying state of attribute " + name, e);
}
}
}
}
if (!srcNew && dstNew) {
if (dstEntity instanceof BaseGenericIdEntity) {
BaseEntityInternalAccess.setNew((BaseGenericIdEntity) dstEntity, false);
BaseEntityInternalAccess.setDetached((BaseGenericIdEntity) dstEntity, true);
} else if (dstEntity instanceof AbstractNotPersistentEntity) {
BaseEntityInternalAccess.setNew((AbstractNotPersistentEntity) dstEntity, false);
}
}
}
@SuppressWarnings("unchecked")
protected void copyValue(Object dstObject, Field field, Object srcValue) throws IllegalAccessException {
if (srcValue instanceof Collection) {
Collection srcCollection = (Collection) srcValue;
Collection dstCollection = (Collection) field.get(dstObject);
Collection newDstCollection = srcValue instanceof List ? new ArrayList() : new LinkedHashSet();
if (dstCollection == null) {
newDstCollection.addAll(srcCollection);
} else {
newDstCollection.addAll(dstCollection);
for (Object o : srcCollection) {
if (!newDstCollection.contains(o))
newDstCollection.add(o);
}
}
field.set(dstObject, newDstCollection);
} else {
field.set(dstObject, srcValue);
}
}
@SuppressWarnings("unchecked")
@Override
public void remove(Entity entity) {
Preconditions.checkNotNullArgument(entity, "entity is null");
if (contains(entity)) {
modifiedInstances.remove(entity);
removedInstances.add(entity);
entity.removePropertyChangeListener(changeListener);
}
}
@Override
public void evict(Entity entity) {
}
@Override
public boolean hasChanges() {
return !(modifiedInstances.isEmpty() && removedInstances.isEmpty());
}
@Override
public void commit() {
PreCommitEvent preCommitEvent = new PreCommitEvent(this, modifiedInstances, removedInstances);
eventRouter.fireEvent(PreCommitListener.class, PreCommitListener::preCommit, preCommitEvent);
if (preCommitEvent.isCommitPrevented())
return;
Set<Entity> committed = performCommit();
PostCommitEvent postCommitEvent = new PostCommitEvent(this, committed);
eventRouter.fireEvent(PostCommitListener.class, PostCommitListener::postCommit, postCommitEvent);
mergeCommitted(committed);
}
@Override
public void addPreCommitListener(PreCommitListener listener) {
eventRouter.addListener(PreCommitListener.class, listener);
}
@Override
public void removePreCommitListener(PreCommitListener listener) {
eventRouter.removeListener(PreCommitListener.class, listener);
}
@Override
public void addPostCommitListener(PostCommitListener listener) {
eventRouter.addListener(PostCommitListener.class, listener);
}
@Override
public void removePostCommitListener(PostCommitListener listener) {
eventRouter.removeListener(PostCommitListener.class, listener);
}
protected Set<Entity> performCommit() {
if (!hasChanges())
return Collections.emptySet();
if (parentContext == null) {
return commitToDataManager();
} else {
return commitToParentContext();
}
}
protected Set<Entity> commitToDataManager() {
CommitContext commitContext = new CommitContext(modifiedInstances, removedInstances);
return dataManager.commit(commitContext);
}
protected Set<Entity> commitToParentContext() {
HashSet<Entity> committedEntities = new HashSet<>();
for (Entity entity : modifiedInstances) {
committedEntities.add(parentContext.merge(entity));
}
for (Entity entity : removedInstances) {
parentContext.remove(entity);
}
return committedEntities;
}
protected void mergeCommitted(Set<Entity> committed) {
for (Entity entity : committed) {
if (contains(entity)) {
merge(entity, false);
}
}
}
protected Collection<Entity> getAll() {
List<Entity> resultList = new ArrayList<>();
for (Map<Object, Entity> entityMap : content.values()) {
resultList.addAll(entityMap.values());
}
return resultList;
}
protected class ChangeListener implements Instance.PropertyChangeListener {
@Override
public void propertyChanged(Instance.PropertyChangeEvent e) {
if (!disableListeners) {
modifiedInstances.add((Entity) e.getItem());
}
}
}
protected class MergingAttributeVisitor implements EntityAttributeVisitor {
@Override
public boolean skip(MetaProperty property) {
return !property.getRange().isClass() || property.isReadOnly();
}
@Override
public void visit(Entity e, MetaProperty property) {
if (!entityStates.isLoaded(e, property.getName()))
return;
Object value = e.getValue(property.getName());
if (value != null) {
if (value instanceof Collection) {
if (value instanceof List) {
mergeList((List) value, e, property.getName());
} else if (value instanceof Set) {
mergeSet((Set) value, e, property.getName());
} else {
throw new UnsupportedOperationException("Unsupported collection type: " + value.getClass().getName());
}
} else {
mergeInstance((Entity) value, e, property.getName());
}
}
}
@SuppressWarnings("unchecked")
protected void mergeList(List list, Entity owningEntity, String propertyName) {
for (ListIterator<Entity> it = list.listIterator(); it.hasNext();) {
Entity entity = it.next();
Entity managed = internalMerge(entity);
if (managed != entity) {
it.set(managed);
}
}
if (!(list instanceof ObservableList)) {
ObservableList observableList = new ObservableList<>(list, () -> modified(owningEntity));
((AbstractInstance) owningEntity).setValue(propertyName, observableList, false);
}
}
@SuppressWarnings("unchecked")
protected void mergeSet(Set set, Entity owningEntity, String propertyName) {
for (Entity entity : new ArrayList<Entity>(set)) {
Entity managed = internalMerge(entity);
if (managed != entity) {
set.remove(entity);
set.add(managed);
}
}
if (!(set instanceof ObservableList)) {
ObservableSet observableSet = new ObservableSet<>(set, () -> modified(owningEntity));
((AbstractInstance) owningEntity).setValue(propertyName, observableSet, false);
}
}
protected void mergeInstance(Entity entity, Entity owningEntity, String propertyName) {
Entity managed = internalMerge(entity);
if (managed != entity) {
((AbstractInstance) owningEntity).setValue(propertyName, managed, false);
}
}
protected void modified(Entity entity) {
if (!disableListeners) {
modifiedInstances.add(entity);
}
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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.model.impl;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.model.DataContext;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.InstanceLoader;
import javax.annotation.Nullable;
/**
*
*/
public class StandardInstanceLoader<T extends Entity<K>, K> implements InstanceLoader<T, K> {
private Metadata metadata;
private DataManager dataManager;
private DataContext dataContext;
private InstanceContainer<T> container;
private K entityId;
private boolean softDeletion;
private View view;
private String viewName;
public StandardInstanceLoader(Metadata metadata, DataManager dataManager) {
this.metadata = metadata;
this.dataManager = dataManager;
}
@Nullable
@Override
public DataContext getDataContext() {
return dataContext;
}
@Override
public void setDataContext(DataContext dataContext) {
this.dataContext = dataContext;
}
@Override
public void load() {
if (container == null)
throw new IllegalStateException("container is null");
if (entityId == null)
throw new IllegalStateException("entityId is null");
@SuppressWarnings("unchecked")
LoadContext<T> loadContext = LoadContext.create(container.getMetaClass().getJavaClass());
loadContext.setId(entityId);
if (view == null && viewName != null) {
this.view = metadata.getViewRepository().getView(container.getMetaClass(), viewName);
}
if (view != null) {
loadContext.setView(view);
}
T entity = dataManager.load(loadContext);
if (dataContext != null) {
dataContext.merge(entity);
}
container.setItem(entity);
}
@Override
public InstanceContainer<T> getContainer() {
return container;
}
@Override
public void setContainer(InstanceContainer<T> container) {
this.container = container;
}
@Override
public K getEntityId() {
return entityId;
}
@Override
public void setEntityId(K entityId) {
this.entityId = entityId;
}
@Override
public boolean isSoftDeletion() {
return softDeletion;
}
@Override
public void setSoftDeletion(boolean softDeletion) {
this.softDeletion = softDeletion;
}
@Override
public View getView() {
return view;
}
@Override
public void setView(View view) {
this.view = view;
}
@Override
public void setView(String viewName) {
if (this.view != null)
throw new IllegalStateException("view is already set");
this.viewName = viewName;
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.model.impl;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionContainer.CollectionChangeListener;
import java.lang.ref.WeakReference;
public class WeakCollectionChangeListener implements CollectionChangeListener {
private final WeakReference<CollectionChangeListener> reference;
private final CollectionContainer collectionDatasource;
public WeakCollectionChangeListener(CollectionContainer collectionDatasource,
CollectionChangeListener collectionChangeListener) {
this.collectionDatasource = collectionDatasource;
this.reference = new WeakReference<>(collectionChangeListener);
}
@SuppressWarnings("unchecked")
@Override
public void collectionChanged(CollectionContainer.CollectionChangeEvent e) {
CollectionChangeListener collectionChangeListener = reference.get();
if (collectionChangeListener != null) {
collectionChangeListener.collectionChanged(e);
} else {
collectionDatasource.removeCollectionChangeListener(this);
}
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.model.impl;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.InstanceContainer;
import java.lang.ref.WeakReference;
public class WeakContainerListenerAdapter implements InstanceContainer.ItemPropertyChangeListener, /*EntityContainer.StateChangeListener,*/ CollectionContainer.CollectionChangeListener {
private final CollectionContainer collectionDatasource;
private final WeakReference<InstanceContainer.ItemPropertyChangeListener> itemPropertyChangeListenerReference;
// private final WeakReference<EntityContainer.StateChangeListener> stateChangeListenerReference;
private final WeakReference<CollectionContainer.CollectionChangeListener> collectionChangeListenerReference;
public WeakContainerListenerAdapter(CollectionContainer datasource, InstanceContainer.ItemPropertyChangeListener itemPropertyChangeListener,
/*EntityContainer.StateChangeListener stateChangeListener,*/ CollectionContainer.CollectionChangeListener collectionChangeListener) {
this.collectionDatasource = datasource;
this.itemPropertyChangeListenerReference = new WeakReference<>(itemPropertyChangeListener);
// this.stateChangeListenerReference = new WeakReference<>(stateChangeListener);
this.collectionChangeListenerReference = new WeakReference<>(collectionChangeListener);
}
@SuppressWarnings("unchecked")
@Override
public void collectionChanged(CollectionContainer.CollectionChangeEvent e) {
CollectionContainer.CollectionChangeListener collectionChangeListener = collectionChangeListenerReference.get();
if (collectionChangeListener != null) {
collectionChangeListener.collectionChanged(e);
} else {
collectionDatasource.removeCollectionChangeListener(this);
}
}
@SuppressWarnings("unchecked")
@Override
public void itemPropertyChanged(InstanceContainer.ItemPropertyChangeEvent e) {
InstanceContainer.ItemPropertyChangeListener itemPropertyChangeListener = itemPropertyChangeListenerReference.get();
if (itemPropertyChangeListener != null) {
itemPropertyChangeListener.itemPropertyChanged(e);
} else {
collectionDatasource.removeItemPropertyChangeListener(this);
}
}
// @SuppressWarnings("unchecked")
// @Override
// public void stateChanged(EntityContainer.StateChangeEvent e) {
// EntityContainer.StateChangeListener stateChangeListener = stateChangeListenerReference.get();
// if (stateChangeListener != null) {
// stateChangeListener.stateChanged(e);
// } else {
// collectionDatasource.removeStateChangeListener(this);
// }
// }
}

View File

@ -0,0 +1,44 @@
/*
* 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.model.impl;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.InstanceContainer.ItemChangeListener;
import java.lang.ref.WeakReference;
public class WeakItemChangeListener implements ItemChangeListener {
private final InstanceContainer container;
private final WeakReference<ItemChangeListener> reference;
public WeakItemChangeListener(InstanceContainer datasource, ItemChangeListener itemChangeListener) {
this.container = datasource;
this.reference = new WeakReference<>(itemChangeListener);
}
@SuppressWarnings("unchecked")
@Override
public void itemChanged(InstanceContainer.ItemChangeEvent e) {
ItemChangeListener itemChangeListener = reference.get();
if (itemChangeListener != null) {
itemChangeListener.itemChanged(e);
} else {
container.removeItemChangeListener(this);
}
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.model.impl;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.InstanceContainer.ItemPropertyChangeEvent;
import com.haulmont.cuba.gui.model.InstanceContainer.ItemPropertyChangeListener;
import java.lang.ref.WeakReference;
public class WeakItemPropertyChangeListener implements ItemPropertyChangeListener {
private final InstanceContainer datasource;
private final WeakReference<ItemPropertyChangeListener> reference;
public WeakItemPropertyChangeListener(InstanceContainer datasource,
ItemPropertyChangeListener itemPropertyChangeListener) {
this.datasource = datasource;
this.reference = new WeakReference<>(itemPropertyChangeListener);
}
@SuppressWarnings("unchecked")
@Override
public void itemPropertyChanged(ItemPropertyChangeEvent e) {
ItemPropertyChangeListener itemPropertyChangeListener = reference.get();
if (itemPropertyChangeListener != null) {
itemPropertyChangeListener.itemPropertyChanged(e);
} else {
datasource.removeItemPropertyChangeListener(this);
}
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.model.impl;
import com.haulmont.cuba.core.sys.serialization.Serialization;
import com.haulmont.cuba.core.sys.serialization.StandardSerialization;
import com.haulmont.cuba.security.entity.Role;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.entity.UserRole;
import org.junit.Test;
import java.util.ArrayList;
import static org.junit.Assert.*;
/**
*
*/
public class ObservableListTest {
@Test
public void testSerialization() throws Exception {
Serialization serialization = new StandardSerialization();
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
user1.setUserRoles(new ObservableList<>(new ArrayList<>(), () -> {}));
Role role1 = new Role();
role1.setName("Role 1");
UserRole user1Role1 = new UserRole();
user1Role1.setUser(user1);
user1Role1.setRole(role1);
user1.getUserRoles().add(user1Role1);
User deserializedUser = (User) serialization.deserialize(serialization.serialize(user1));
assertTrue(deserializedUser.getUserRoles() instanceof ArrayList);
}
}

View File

@ -0,0 +1,438 @@
/*
* 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.model.impl;
import com.haulmont.cuba.client.testsupport.CubaClientTestCase;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.EntityStates;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.Role;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.entity.UserRole;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
import static org.junit.Assert.*;
public class StandardDataContextTest extends CubaClientTestCase {
private Metadata metadata;
private DataManager dataManager;
private EntityStates entityStates;
@Before
public void setUp() throws Exception {
addEntityPackage("com.haulmont.cuba");
setupInfrastructure();
metadata = AppBeans.get(Metadata.class);
dataManager = AppBeans.get(DataManager.class);
entityStates = AppBeans.get(EntityStates.class);
}
@Test
public void testMerge() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates);
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
User mergedUser1 = context.merge(user1);
assertTrue(mergedUser1 == context.find(User.class, user1.getId()));
User user11 = new User();
user11.setLogin("u11");
user11.setName("User 11");
user11.setId(user1.getId());
User mergedUser11 = context.merge(user11);
assertTrue(mergedUser11 == mergedUser1);
assertTrue(mergedUser11 != user11);
}
@Test
public void testMergeGraph() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates);
// an object being merged
User user1 = new User();
entityStates.makeDetached(user1);
user1.setLogin("u1");
user1.setName("User 1");
user1.setUserRoles(new ArrayList<>());
Role role1 = new Role();
entityStates.makeDetached(role1);
role1.setName("Role 1");
UserRole user1Role1 = new UserRole();
entityStates.makeDetached(user1Role1);
user1Role1.setUser(user1);
user1Role1.setRole(role1);
user1.getUserRoles().add(user1Role1);
// somewhere in the object graph another object with the same id
User user11 = new User();
entityStates.makeDetached(user11);
user11.setLogin("u11");
user11.setName("User 11");
user11.setId(user1.getId());
UserRole user11Role1 = new UserRole();
entityStates.makeDetached(user11Role1);
user11Role1.setUser(user11);
user11Role1.setRole(role1);
user1.getUserRoles().add(user11Role1);
User mergedUser1 = context.merge(user1);
// instance of the first object
assertTrue(mergedUser1 == context.find(User.class, user1.getId()));
// local attributes of the second object
assertEquals("u11", mergedUser1.getLogin());
assertEquals("User 11", mergedUser1.getName());
assertTrue(user1Role1 == context.find(UserRole.class, user1Role1.getId()));
assertTrue(user11Role1 == context.find(UserRole.class, user11Role1.getId()));
assertTrue(role1 == context.find(Role.class, role1.getId()));
assertTrue(mergedUser1.getUserRoles().get(1).getUser() == mergedUser1);
assertFalse(context.hasChanges());
}
@Test
public void testMergeGraph_firstObjectWithNullCollection() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates);
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
Role role1 = new Role();
role1.setName("Role 1");
User user11 = new User();
user11.setLogin("u11");
user11.setName("User 11");
user11.setId(user1.getId());
UserRole user11Role1 = new UserRole();
user11Role1.setUser(user11);
user11Role1.setRole(role1);
user11.setUserRoles(new ArrayList<>());
user11.getUserRoles().add(user11Role1);
User mergedUser1 = context.merge(user1);
User mergedUser11 = context.merge(user11);
assertTrue(mergedUser11 == mergedUser1);
// instance of the first object
assertTrue(mergedUser1 == context.find(User.class, user1.getId()));
// local attributes of the second object
assertEquals("u11", mergedUser1.getLogin());
assertEquals("User 11", mergedUser1.getName());
// collection of the second object
assertNotNull(mergedUser1.getUserRoles());
assertTrue(mergedUser1.getUserRoles().get(0).getUser() == mergedUser1);
assertTrue(user11Role1 == context.find(UserRole.class, user11Role1.getId()));
assertTrue(role1 == context.find(Role.class, role1.getId()));
}
@Test
public void testMergedNew() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates) {
@Override
protected Set<Entity> performCommit() {
return Collections.emptySet();
}
};
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
user1.setUserRoles(new ArrayList<>());
Role role1 = new Role();
role1.setName("Role 1");
Role role2 = new Role();
role1.setName("Role 2");
UserRole user1Role1 = new UserRole();
user1Role1.setUser(user1);
user1Role1.setRole(role1);
user1.getUserRoles().add(user1Role1);
UserRole user1Role2 = new UserRole();
user1Role2.setUser(user1);
user1Role2.setRole(role2);
user1.getUserRoles().add(user1Role2);
context.merge(user1);
context.addPreCommitListener(e -> {
assertEquals(5, e.getModifiedInstances().size());
assertTrue(e.getModifiedInstances().contains(user1));
assertTrue(e.getModifiedInstances().contains(role1));
assertTrue(e.getModifiedInstances().contains(role2));
assertTrue(e.getModifiedInstances().contains(user1Role1));
assertTrue(e.getModifiedInstances().contains(user1Role2));
assertEquals(0, e.getRemovedInstances().size());
});
context.commit();
}
@Test
public void testModified() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates) {
@Override
protected Set<Entity> performCommit() {
return Collections.emptySet();
}
};
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
user1.setUserRoles(new ArrayList<>());
entityStates.makeDetached(user1);
Role role1 = new Role();
role1.setName("Role 1");
entityStates.makeDetached(role1);
Role role2 = new Role();
role1.setName("Role 2");
entityStates.makeDetached(role2);
UserRole user1Role1 = new UserRole();
user1Role1.setUser(user1);
user1Role1.setRole(role1);
entityStates.makeDetached(user1Role1);
user1.getUserRoles().add(user1Role1);
UserRole user1Role2 = new UserRole();
user1Role2.setUser(user1);
user1Role2.setRole(role2);
entityStates.makeDetached(user1Role2);
user1.getUserRoles().add(user1Role2);
context.merge(user1);
role1.setName("Role 1 modified");
user1.getUserRoles().remove(user1Role2);
context.remove(user1Role2);
context.addPreCommitListener(e -> {
assertEquals(2, e.getModifiedInstances().size());
assertTrue(e.getModifiedInstances().contains(role1));
assertTrue(e.getModifiedInstances().contains(user1));
assertEquals(1, e.getRemovedInstances().size());
assertTrue(e.getRemovedInstances().contains(user1Role2));
});
context.commit();
}
@Test
public void testCopyState() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates);
User src, dst;
// (1) src.new > dst.new : copy all non-null
src = new User();
src.setLogin("u-src");
dst = new User();
dst.setId(src.getId());
dst.setLogin("u-dst");
dst.setName("Dest User");
dst.setUserRoles(new ArrayList<>());
context.copyState(src, dst);
assertTrue(entityStates.isNew(dst));
assertNull(dst.getVersion());
assertEquals("u-src", dst.getLogin());
assertEquals("Dest User", dst.getName());
assertNotNull(dst.getUserRoles());
// (2) src.new -> dst.det : do nothing
src = new User();
src.setLogin("u-src");
dst = new User();
dst.setId(src.getId());
dst.setVersion(1);
dst.setLogin("u-dst");
dst.setName("Dest User");
dst.setUserRoles(new ArrayList<>());
entityStates.makeDetached(dst);
context.copyState(src, dst);
assertTrue(entityStates.isDetached(dst));
assertNotNull(dst.getVersion());
assertEquals("u-dst", dst.getLogin());
assertEquals("Dest User", dst.getName());
assertNotNull(dst.getUserRoles());
// (3) src.det -> dst.new : copy all loaded, make detached
src = new User();
src.setVersion(1);
src.setLogin("u-src");
entityStates.makeDetached(src);
dst = new User();
dst.setId(src.getId());
dst.setLogin("u-dst");
dst.setName("Dest User");
dst.setUserRoles(new ArrayList<>());
context.copyState(src, dst);
assertTrue(entityStates.isDetached(dst));
assertEquals(Integer.valueOf(1), dst.getVersion());
assertEquals("u-src", dst.getLogin());
assertNull(dst.getName());
assertNotNull(dst.getUserRoles());
// (4) src.det -> dst.det : if src.version >= dst.version, copy all loaded
src = new User();
src.setVersion(2);
src.setLogin("u-src");
entityStates.makeDetached(src);
dst = new User();
dst.setId(src.getId());
dst.setVersion(1);
dst.setLogin("u-dst");
dst.setName("Dest User");
dst.setUserRoles(new ArrayList<>());
entityStates.makeDetached(dst);
context.copyState(src, dst);
assertTrue(entityStates.isDetached(dst));
assertEquals(Integer.valueOf(2), dst.getVersion());
assertEquals("u-src", dst.getLogin());
assertNull(dst.getName());
assertNotNull(dst.getUserRoles());
// (4) src.det -> dst.det : if src.version < dst.version, do nothing
src = new User();
src.setVersion(1);
src.setLogin("u-src");
entityStates.makeDetached(src);
dst = new User();
dst.setId(src.getId());
dst.setVersion(2);
dst.setLogin("u-dst");
dst.setName("Dest User");
dst.setUserRoles(new ArrayList<>());
entityStates.makeDetached(dst);
context.copyState(src, dst);
assertTrue(entityStates.isDetached(dst));
assertEquals(Integer.valueOf(2), dst.getVersion());
assertEquals("u-dst", dst.getLogin());
assertEquals("Dest User", dst.getName());
assertNotNull(dst.getUserRoles());
}
@Test
public void testParentContext() throws Exception {
StandardDataContext context = new StandardDataContext(metadata, dataManager, entityStates) {
@Override
protected Set<Entity> commitToDataManager() {
return Collections.emptySet();
}
};
User user1 = new User();
user1.setLogin("u1");
user1.setName("User 1");
user1.setUserRoles(new ArrayList<>());
context.merge(user1);
StandardDataContext childContext = new StandardDataContext(metadata, dataManager, entityStates);
childContext.setParent(context);
User user1InChild = childContext.find(User.class, user1.getId());
assertNotNull(user1InChild);
assertTrue(user1InChild != user1);
UserRole user1Role1 = new UserRole();
user1Role1.setUser(user1InChild);
assertNotNull(user1InChild.getUserRoles());
user1InChild.getUserRoles().add(user1Role1);
childContext.merge(user1Role1);
childContext.addPreCommitListener(e -> {
assertEquals(2, e.getModifiedInstances().size());
assertTrue(e.getModifiedInstances().stream().anyMatch(entity -> entity == user1InChild));
assertTrue(e.getModifiedInstances().stream().anyMatch(entity -> entity == user1Role1));
});
childContext.commit();
assertNotNull(user1.getUserRoles());
assertEquals(1, user1.getUserRoles().size());
context.addPreCommitListener(e -> {
assertEquals(2, e.getModifiedInstances().size());
assertTrue(e.getModifiedInstances().stream().anyMatch(entity -> entity == user1));
assertTrue(e.getModifiedInstances().stream().anyMatch(entity -> entity == user1Role1));
});
context.commit();
}
}

View File

@ -508,7 +508,7 @@ public class CubaFoldersPane extends VerticalLayout {
protected Component createSearchFoldersPane() {
searchFoldersTree = new CubaTree();
searchFoldersTree.setSelectable(true);
searchFoldersLabel.setCubaId("searchFoldersTree");
searchFoldersTree.setCubaId("searchFoldersTree");
searchFoldersTree.setItemStyleGenerator(new FolderTreeStyleProvider());
searchFoldersTree.addShortcutListener(new ShortcutListener("applySearchFolder", ShortcutAction.KeyCode.ENTER, (int[]) null) {
@Override

View File

@ -28,36 +28,31 @@ import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.BeanValidation;
import com.haulmont.cuba.core.global.MessageTools;
import com.haulmont.cuba.core.global.MetadataTools;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.Field;
import com.haulmont.cuba.gui.components.RequiredValueMissingException;
import com.haulmont.cuba.gui.components.ValidationException;
import com.haulmont.cuba.gui.components.ValidationFailedException;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.compatibility.ComponentValueListenerWrapper;
import com.haulmont.cuba.gui.components.validators.BeanValidator;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.data.ValueListener;
import com.haulmont.cuba.gui.data.impl.WeakItemChangeListener;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.web.gui.data.ItemWrapper;
import com.haulmont.cuba.web.gui.model.ItemAdapter;
import com.vaadin.ui.Component.HasContextHelp.ContextHelpIconClickListener;
import org.apache.commons.lang.StringUtils;
import javax.validation.constraints.NotNull;
import javax.validation.metadata.BeanDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.function.Consumer;
import static com.haulmont.cuba.gui.ComponentsHelper.handleFilteredAttributes;
public abstract class WebAbstractField<T extends com.vaadin.v7.ui.AbstractField>
extends WebAbstractComponent<T> implements Field {
extends WebAbstractComponent<T> implements Field, PropertyBoundComponent /* todo ds: move to Field */ {
protected static final int VALIDATORS_LIST_INITIAL_CAPACITY = 4;
protected InstanceContainer instanceContainer;
protected Datasource<Entity> datasource;
protected MetaProperty metaProperty;
protected MetaPropertyPath metaPropertyPath;
@ -69,6 +64,7 @@ public abstract class WebAbstractField<T extends com.vaadin.v7.ui.AbstractField>
protected boolean editable = true;
protected ItemWrapper itemWrapper;
protected ItemAdapter itemAdapter;
protected Datasource.ItemChangeListener<Entity> securityItemChangeListener;
protected WeakItemChangeListener securityWeakItemChangeListener;
@ -488,4 +484,67 @@ public abstract class WebAbstractField<T extends com.vaadin.v7.ui.AbstractField>
contextHelpIconClickHandler.accept(event);
}
}
@Override
public InstanceContainer getEntityContainer() {
return instanceContainer;
}
@Override
public void setContainer(InstanceContainer container, String property) {
if (this.instanceContainer != null) {
metaProperty = null;
metaPropertyPath = null;
component.setPropertyDataSource(null);
// todo dc
// //noinspection unchecked
// this.entityContainer.removeItemChangeListener(securityWeakItemChangeListener);
// securityWeakItemChangeListener = null;
this.instanceContainer = null;
if (itemAdapter != null) {
itemAdapter.unsubscribe();
}
disableBeanValidator();
}
if (container != null) {
//noinspection unchecked
this.instanceContainer = container;
final MetaClass metaClass = container.getMetaClass();
resolveMetaPropertyPath(metaClass, property);
initFieldConverter();
itemAdapter = createItemAdapter(container, Collections.singleton(metaPropertyPath));
component.setPropertyDataSource(itemAdapter.getItemProperty(metaPropertyPath));
initRequired(metaPropertyPath);
if (metaProperty.isReadOnly()) {
setEditable(false);
}
// todo dc
// handleFilteredAttributes(this, this.datasource, metaPropertyPath);
// securityItemChangeListener = e -> handleFilteredAttributes(this, this.datasource, metaPropertyPath);
//
// securityWeakItemChangeListener = new WeakItemChangeListener(datasource, securityItemChangeListener);
// //noinspection unchecked
// this.datasource.addItemChangeListener(securityWeakItemChangeListener);
initBeanValidator();
}
}
protected ItemAdapter createItemAdapter(InstanceContainer container, Collection<MetaPropertyPath> propertyPaths) {
return new ItemAdapter(container, container.getMetaClass(), propertyPaths);
}
}

View File

@ -21,6 +21,7 @@ import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.gui.components.Action;
import com.haulmont.cuba.gui.components.ListComponent;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.vaadin.v7.ui.AbstractSelect;
import javax.annotation.Nullable;
@ -36,6 +37,7 @@ public abstract class WebAbstractList<T extends AbstractSelect, E extends Entity
ListComponent<E> {
protected CollectionDatasource datasource;
protected CollectionContainer container;
@Override
public boolean isMultiSelect() {
@ -62,7 +64,7 @@ public abstract class WebAbstractList<T extends AbstractSelect, E extends Entity
if (itemIds != null) {
Set res = new LinkedHashSet<>();
for (Object id : itemIds) {
Entity item = datasource.getItem(id);
Entity item = container != null ? container.getItem(id) : datasource.getItem(id);
if (item != null)
res.add(item);
}
@ -101,8 +103,13 @@ public abstract class WebAbstractList<T extends AbstractSelect, E extends Entity
public void setSelected(Collection<E> items) {
Set itemIds = new HashSet();
for (Entity item : items) {
if (!datasource.containsItem(item.getId())) {
throw new IllegalStateException("Datasource doesn't contain item to select: " + item);
boolean found = true;
if (container != null)
found = container.getItem(item.getId()) != null;
else if (datasource != null)
found = datasource.containsItem(item.getId());
if (!found) {
throw new IllegalStateException("Collection doesn't contain item to select: " + item);
}
itemIds.add(item.getId());
}

View File

@ -47,6 +47,7 @@ import com.haulmont.cuba.gui.data.aggregation.Aggregation;
import com.haulmont.cuba.gui.data.aggregation.Aggregations;
import com.haulmont.cuba.gui.data.impl.CollectionDsListenersWrapper;
import com.haulmont.cuba.gui.data.impl.DatasourceImplementation;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.presentations.Presentations;
import com.haulmont.cuba.gui.presentations.PresentationsImpl;
import com.haulmont.cuba.gui.theme.ThemeConstants;
@ -59,6 +60,7 @@ import com.haulmont.cuba.web.gui.data.CollectionDsWrapper;
import com.haulmont.cuba.web.gui.data.ItemWrapper;
import com.haulmont.cuba.web.gui.data.PropertyWrapper;
import com.haulmont.cuba.web.gui.icons.IconResolver;
import com.haulmont.cuba.web.gui.model.CollectionContainerAdapter;
import com.haulmont.cuba.web.widgets.CubaEnhancedTable;
import com.haulmont.cuba.web.widgets.CubaResizableTextAreaWrapper;
import com.haulmont.cuba.web.widgets.CubaTextArea;
@ -147,6 +149,8 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
protected CollectionDsListenersWrapper collectionDsListenersWrapper;
protected CollectionContainer.CollectionChangeListener containerCollectionChangeListener;
protected CollectionDsWrapper containerDatasource;
protected boolean ignoreUnfetchedAttributes = false;
@ -673,14 +677,16 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
shortcutsDelegate.setAllowEnterShortcut(false);
component.addValueChangeListener(event -> {
if (datasource == null) {
return;
}
final Set<? extends Entity> selected = getSelected();
if (selected.isEmpty()) {
Entity dsItem = datasource.getItemIfValid();
datasource.setItem(null);
Entity dsItem = null;
if (datasource != null) {
dsItem = datasource.getItemIfValid();
datasource.setItem(null);
} else {
dsItem = container.getItem();
container.setItem(null);
}
if (dsItem == null) {
// in this case item change event will not be generated
refreshActionsState();
@ -688,12 +694,21 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
} else {
// reset selection and select new item
if (isMultiSelect()) {
datasource.setItem(null);
if (datasource != null)
datasource.setItem(null);
else
container.setItem(null);
}
Entity newItem = selected.iterator().next();
Entity dsItem = datasource.getItemIfValid();
datasource.setItem(newItem);
Entity dsItem;
if (datasource != null) {
dsItem = datasource.getItemIfValid();
datasource.setItem(newItem);
} else {
dsItem = container.getItem();
container.setItem(newItem);
}
if (Objects.equals(dsItem, newItem)) {
// in this case item change event will not be generated
@ -1042,7 +1057,7 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
createStubsForGeneratedColumns();
setVisibleColumns(getInitialVisibleColumns());
setVisibleColumns(getInitialVisibleColumns(datasource.getMetaClass()));
if (security.isSpecificPermitted(ShowInfoAction.ACTION_PERMISSION)) {
ShowInfoAction action = (ShowInfoAction) getAction(ShowInfoAction.ACTION_ID);
@ -1073,6 +1088,187 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
return new TableCollectionDsListenersWrapper();
}
@Override
public void setContainer(CollectionContainer container) {
Preconditions.checkNotNullArgument(container, "container is null");
if (this.container != null) {
throw new UnsupportedOperationException("Changing container is not supported by the Table component");
}
MessageTools messageTools = AppBeans.get(MessageTools.NAME);
final Collection<Object> columns;
// if (this.columns.isEmpty()) {
// Collection<MetaPropertyPath> paths = datasource.getView() != null ?
// // if a view is specified - use view properties
// metadataTools.getViewPropertyPaths(datasource.getView(), datasource.getMetaClass()) :
// // otherwise use all properties from meta-class
// metadataTools.getPropertyPaths(datasource.getMetaClass());
// for (MetaPropertyPath metaPropertyPath : paths) {
// MetaProperty property = metaPropertyPath.getMetaProperty();
// if (!property.getRange().getCardinality().isMany() && !metadataTools.isSystem(property)) {
// Table.Column column = new Table.Column(metaPropertyPath);
//
// String propertyName = property.getName();
// MetaClass propertyMetaClass = metadataTools.getPropertyEnclosingMetaClass(metaPropertyPath);
//
// column.setCaption(messageTools.getPropertyCaption(propertyMetaClass, propertyName));
// column.setType(metaPropertyPath.getRangeJavaClass());
//
// Element element = DocumentHelper.createElement("column");
// column.setXmlDescriptor(element);
//
// addColumn(column);
// }
// }
// }
columns = this.columns.keySet();
this.container = container;
// drop cached datasources for components before update table cells on client
// collectionChangeListener = e -> {
// if (fieldDatasources != null) {
// switch (e.getOperation()) {
// case CLEAR:
// case REFRESH:
// fieldDatasources.clear();
// break;
//
// case UPDATE:
// case REMOVE:
// for (Object entity : e.getItems()) {
// fieldDatasources.remove(entity);
// }
// break;
// }
// }
// };
//noinspection unchecked
this.container.addCollectionChangeListener(
new com.haulmont.cuba.gui.model.impl.WeakCollectionChangeListener(this.container, containerCollectionChangeListener));
CollectionContainerAdapter containerAdapter = createContainerAdapter(this.container, getPropertyColumns());
component.setContainerDataSource(containerAdapter);
List<MetaPropertyPath> editableColumns = null;
if (isEditable()) {
editableColumns = new LinkedList<>();
}
MetaClass metaClass = this.container.getMetaClass();
for (final Object columnId : columns) {
final Table.Column column = this.columns.get(columnId);
final String caption;
if (column != null) {
caption = StringUtils.capitalize(column.getCaption() != null ? column.getCaption() : getColumnCaption(columnId));
} else {
caption = StringUtils.capitalize(getColumnCaption(columnId));
}
setColumnHeader(columnId, caption);
if (column != null) {
if (editableColumns != null && column.isEditable() && (columnId instanceof MetaPropertyPath)) {
MetaPropertyPath propertyPath = ((MetaPropertyPath) columnId);
if (security.isEntityAttrUpdatePermitted(metaClass, propertyPath.toString())) {
editableColumns.add(propertyPath);
}
}
if (column.isCollapsed() && component.isColumnCollapsingAllowed()) {
component.setColumnCollapsed(column.getId(), true);
}
if (column.getAggregation() != null && isAggregatable()) {
checkAggregation(column.getAggregation());
component.addContainerPropertyAggregation(column.getId(),
WebComponentsHelper.convertAggregationType(column.getAggregation().getType()));
}
}
}
if (editableColumns != null && !editableColumns.isEmpty()) {
setEditableColumns(editableColumns);
}
createColumns(containerAdapter);
for (Table.Column column : this.columnsOrder) {
if (editable && column.getAggregation() != null
&& (BooleanUtils.isTrue(column.isEditable()) || BooleanUtils.isTrue(column.isCalculatable()))) {
addAggregationCell(column);
}
}
// aggregationDatasourceListener = createAggregationDatasourceListener();
// //noinspection unchecked
// collectionContainer.addItemPropertyChangeListener(
// new com.haulmont.cuba.gui.model.impl.WeakItemPropertyChangeListener(collectionContainer, aggregationDatasourceListener));
createStubsForGeneratedColumns();
setVisibleColumns(getInitialVisibleColumns(this.container.getMetaClass()));
// if (security.isSpecificPermitted(ShowInfoAction.ACTION_PERMISSION)) {
// ShowInfoAction action = (ShowInfoAction) getAction(ShowInfoAction.ACTION_ID);
// if (action == null) {
// action = new ShowInfoAction();
// addAction(action);
// }
// action.setDatasource(datasource);
// }
// if (rowsCount != null) {
// rowsCount.setDatasource(datasource);
// }
// collectionChangeSelectionListener = e -> {
// // #PL-2035, reload selection from ds
// Set<Object> selectedItemIds = getSelectedItemIds();
// if (selectedItemIds == null) {
// selectedItemIds = Collections.emptySet();
// }
//
// Set<Object> newSelection = new HashSet<>();
// for (Object entityId : selectedItemIds) {
// //noinspection unchecked
// if (e.getDs().containsItem(entityId)) {
// newSelection.add(entityId);
// }
// }
//
// if (e.getDs().getState() == Datasource.State.VALID && e.getDs().getItem() != null) {
// newSelection.add(e.getDs().getItem().getId());
// }
//
// if (newSelection.isEmpty()) {
// setSelected((E) null);
// } else {
// setSelectedIds(newSelection);
// }
// };
// //noinspection unchecked
// datasource.addCollectionChangeListener(new WeakCollectionChangeListener(datasource, collectionChangeSelectionListener));
//noinspection unchecked
// collectionDsActionsNotifier = new CollectionDsActionsNotifier(this);
// collectionDsActionsNotifier.bind(datasource);
// for (Action action : getActions()) {
// action.refreshState();
// }
// if (!canBeSorted(datasource))
// setSortable(false);
assignAutoDebugId();
}
protected boolean canBeSorted(CollectionDatasource datasource) {
//noinspection SimplifiableConditionalExpression
return datasource instanceof PropertyDatasource ?
@ -1173,10 +1369,9 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
}
}
protected List<Object> getInitialVisibleColumns() {
protected List<Object> getInitialVisibleColumns(MetaClass metaClass) {
List<Object> result = new ArrayList<>();
MetaClass metaClass = datasource.getMetaClass();
for (Column column : columnsOrder) {
if (column.getId() instanceof MetaPropertyPath) {
MetaPropertyPath propertyPath = (MetaPropertyPath) column.getId();
@ -1193,7 +1388,7 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
protected List<MetaPropertyPath> getPropertyColumns() {
List<MetaPropertyPath> result = new ArrayList<>();
MetaClass metaClass = datasource.getMetaClass();
MetaClass metaClass = container != null ? container.getMetaClass() : datasource.getMetaClass();
for (Column column : columnsOrder) {
if (column.getId() instanceof MetaPropertyPath) {
MetaPropertyPath propertyPath = (MetaPropertyPath) column.getId();
@ -1209,6 +1404,11 @@ public abstract class WebAbstractTable<T extends com.vaadin.v7.ui.Table & CubaEn
Collection<MetaPropertyPath> columns,
CollectionDsListenersWrapper collectionDsListenersWrapper);
protected CollectionContainerAdapter createContainerAdapter(CollectionContainer container,
Collection<MetaPropertyPath> columns) {
return new CollectionContainerAdapter(container, columns, true);
};
protected void setVisibleColumns(List<?> columnsOrder) {
component.setVisibleColumns(columnsOrder.toArray());
}

View File

@ -0,0 +1,309 @@
/*
* 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.web.gui.model;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.impl.WeakContainerListenerAdapter;
import com.haulmont.cuba.web.gui.data.StaticItemSetChangeEvent;
import com.haulmont.cuba.web.gui.data.UnsubscribableDsWrapper;
import com.vaadin.ui.UI;
import com.vaadin.v7.data.Container;
import com.vaadin.v7.data.Item;
import com.vaadin.v7.data.Property;
import java.util.*;
import java.util.stream.Collectors;
public class CollectionContainerAdapter implements Container, Container.ItemSetChangeNotifier, UnsubscribableDsWrapper {
protected boolean autoRefresh;
protected boolean ignoreListeners;
protected CollectionContainer<Entity> collectionContainer;
protected Collection<MetaPropertyPath> properties = new ArrayList<>();
// lazily initialized listeners list
protected List<Container.ItemSetChangeListener> itemSetChangeListeners = null;
// protected EntityContainer.StateChangeListener cdsStateChangeListener;
protected InstanceContainer.ItemPropertyChangeListener cdsItemPropertyChangeListener;
protected CollectionContainer.CollectionChangeListener cdsCollectionChangeListener;
protected WeakContainerListenerAdapter weakDsListenerAdapter;
public CollectionContainerAdapter(CollectionContainer collectionContainer, boolean autoRefresh) {
this(collectionContainer, null, autoRefresh);
}
@SuppressWarnings("unchecked")
public CollectionContainerAdapter(CollectionContainer collectionContainer, Collection<MetaPropertyPath> properties,
boolean autoRefresh) {
this.collectionContainer = collectionContainer;
this.autoRefresh = autoRefresh;
// final View view = collectionContainer.getView();
final MetaClass metaClass = collectionContainer.getMetaClass();
// if (properties == null) {
// createProperties(view, metaClass);
// } else {
this.properties.addAll(properties);
// }
cdsItemPropertyChangeListener = createItemPropertyChangeListener();
// cdsStateChangeListener = createStateChangeListener();
cdsCollectionChangeListener = createCollectionChangeListener();
weakDsListenerAdapter = new WeakContainerListenerAdapter(collectionContainer, cdsItemPropertyChangeListener,
/*cdsStateChangeListener,*/ cdsCollectionChangeListener);
collectionContainer.addItemPropertyChangeListener(weakDsListenerAdapter);
// collectionContainer.addStateChangeListener(weakDsListenerAdapter);
collectionContainer.addCollectionChangeListener(weakDsListenerAdapter);
}
protected CollectionContainer.CollectionChangeListener createCollectionChangeListener() {
return new ContainerDatasourceCollectionChangeListener();
}
protected InstanceContainer.ItemPropertyChangeListener createItemPropertyChangeListener() {
return new ContainerDatasourceItemPropertyChangeListener();
}
// protected EntityContainer.StateChangeListener createStateChangeListener() {
// return new ContainerDatasourceStateChangeListener();
// }
// protected void createProperties(View view, MetaClass metaClass) {
// properties.addAll(CollectionDsHelper.createProperties(view, metaClass));
// }
protected void fireItemSetChanged() {
if (ignoreListeners) {
return;
}
ignoreListeners = true;
if (UI.getCurrent().getConnectorTracker().isWritingResponse()) {
// Suppress containerItemSetChange listeners during painting, undefined behavior may be occurred
return;
}
if (itemSetChangeListeners != null) {
StaticItemSetChangeEvent event = new StaticItemSetChangeEvent(this);
for (ItemSetChangeListener listener : itemSetChangeListeners) {
listener.containerItemSetChange(event);
}
}
}
@Override
public Item getItem(Object itemId) {
// CollectionDsHelper.autoRefreshInvalid(collectionContainer, autoRefresh);
//noinspection unchecked
final Object item = collectionContainer.getItem(itemId);
return item == null ? null : getItemAdapter(item);
}
protected Map<Object, ItemAdapter> itemsCache = new HashMap<>();
protected Item getItemAdapter(Object item) {
ItemAdapter wrapper = itemsCache.get(item);
if (wrapper == null) {
wrapper = createItemAdapter(item);
itemsCache.put(item, wrapper);
}
return wrapper;
}
protected ItemAdapter createItemAdapter(Object item) {
return new ItemAdapter(item, collectionContainer.getMetaClass(), properties);
}
@Override
public Collection getContainerPropertyIds() {
return properties;
}
@Override
public Collection getItemIds() {
// CollectionDsHelper.autoRefreshInvalid(collectionContainer, autoRefresh);
return collectionContainer.getItems().stream()
.map(Entity::getId)
.collect(Collectors.toList());
}
@Override
public Property getContainerProperty(Object itemId, Object propertyId) {
final Item item = getItem(itemId);
return item == null ? null : item.getItemProperty(propertyId);
}
@Override
public Class getType(Object propertyId) {
MetaPropertyPath propertyPath = (MetaPropertyPath) propertyId;
return propertyPath.getRangeJavaClass();
}
@Override
public int size() {
// CollectionDsHelper.autoRefreshInvalid(collectionContainer, autoRefresh);
return collectionContainer.getItems().size();
}
@Override
public boolean containsId(Object itemId) {
// CollectionDsHelper.autoRefreshInvalid(collectionContainer, autoRefresh);
//noinspection unchecked
return collectionContainer.getItem(itemId) != null;
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean addContainerProperty(Object propertyId, Class type, Object defaultValue) throws UnsupportedOperationException {
if (propertyId instanceof MetaPropertyPath) {
return this.properties.add((MetaPropertyPath) propertyId);
}
throw new UnsupportedOperationException();
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
//noinspection SuspiciousMethodCalls
return this.properties.remove(propertyId);
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public void addItemSetChangeListener(ItemSetChangeListener listener) {
if (itemSetChangeListeners == null) {
itemSetChangeListeners = new LinkedList<>();
}
itemSetChangeListeners.add(listener);
}
@Override
public void addListener(ItemSetChangeListener listener) {
addItemSetChangeListener(listener);
}
@Override
public void removeItemSetChangeListener(ItemSetChangeListener listener) {
if (itemSetChangeListeners != null) {
itemSetChangeListeners.remove(listener);
if (itemSetChangeListeners.isEmpty()) {
itemSetChangeListeners = null;
}
}
}
@Override
public void removeListener(ItemSetChangeListener listener) {
removeItemSetChangeListener(listener);
}
@SuppressWarnings("unchecked")
@Override
public void unsubscribe() {
collectionContainer.removeCollectionChangeListener(weakDsListenerAdapter);
collectionContainer.removeItemPropertyChangeListener(weakDsListenerAdapter);
// collectionContainer.removeStateChangeListener(weakDsListenerAdapter);
weakDsListenerAdapter = null;
collectionContainer = null;
}
// protected class ContainerDatasourceStateChangeListener implements EntityContainer.StateChangeListener {
//
// public ContainerDatasourceStateChangeListener() {
// }
//
// @Override
// public void stateChanged(EntityContainer.StateChangeEvent e) {
// itemsCache.clear();
// }
// }
protected class ContainerDatasourceCollectionChangeListener implements CollectionContainer.CollectionChangeListener {
public ContainerDatasourceCollectionChangeListener() {
}
@Override
public void collectionChanged(CollectionContainer.CollectionChangeEvent e) {
itemsCache.clear();
final boolean prevIgnoreListeners = ignoreListeners;
try {
fireItemSetChanged();
} finally {
ignoreListeners = prevIgnoreListeners;
}
}
}
protected class ContainerDatasourceItemPropertyChangeListener implements InstanceContainer.ItemPropertyChangeListener {
public ContainerDatasourceItemPropertyChangeListener() {
}
@Override
public void itemPropertyChanged(InstanceContainer.ItemPropertyChangeEvent e) {
Item wrapper = getItemAdapter(e.getItem());
// MetaProperty worked wrong with properties from inherited superclasses
MetaPropertyPath metaPropertyPath = collectionContainer.getMetaClass().getPropertyPath(e.getProperty());
if (metaPropertyPath == null) {
return;
}
Property itemProperty = wrapper.getItemProperty(metaPropertyPath);
if (itemProperty instanceof PropertyAdapter) {
((PropertyAdapter) itemProperty).fireValueChangeEvent();
}
}
}
@Override
public String toString() {
return "{ds=" + (collectionContainer == null ? "null" : collectionContainer.toString() + "}");
}
}

View File

@ -0,0 +1,169 @@
/*
* 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.web.gui.model;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.MetadataTools;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.impl.WeakCollectionChangeListener;
import com.haulmont.cuba.web.gui.data.UnsubscribableDsWrapper;
import com.vaadin.v7.data.Item;
import com.vaadin.v7.data.Property;
import java.util.*;
public class ItemAdapter implements Item, Item.PropertySetChangeNotifier, UnsubscribableDsWrapper {
protected Map<MetaPropertyPath, PropertyAdapter> properties = new HashMap<>();
// lazily initialized listeners list
protected List<PropertySetChangeListener> listeners = null;
protected Object item;
protected MetaClass metaClass;
protected WeakCollectionChangeListener weakCollectionChangeListener;
public ItemAdapter(Object item, MetaClass metaClass) {
this(item, metaClass, AppBeans.<MetadataTools>get(MetadataTools.NAME).getPropertyPaths(metaClass));
}
public ItemAdapter(Object item, MetaClass metaClass, Collection<MetaPropertyPath> properties) {
this.item = item;
this.metaClass = metaClass;
for (MetaPropertyPath property : properties) {
this.properties.put(property, createPropertyModelAdapter(item, property));
}
if (item instanceof CollectionContainer) {
CollectionContainer container = (CollectionContainer) item;
weakCollectionChangeListener = new WeakCollectionChangeListener(container, e -> fireItemPropertySetChanged());
//noinspection unchecked
container.addCollectionChangeListener(weakCollectionChangeListener);
}
}
protected void fireItemPropertySetChanged() {
if (listeners != null) {
PropertySetChangeEvent event = new PropertySetChangeEvent();
for (PropertySetChangeListener listener : listeners) {
listener.itemPropertySetChange(event);
}
}
}
protected PropertyAdapter createPropertyModelAdapter(Object item, MetaPropertyPath propertyPath) {
return new PropertyAdapter(item, propertyPath);
}
@Override
public Property getItemProperty(Object id) {
if (id instanceof MetaPropertyPath) {
return properties.get(id);
} else if (id instanceof MetaProperty) {
final MetaProperty metaProperty = (MetaProperty) id;
return properties.get(new MetaPropertyPath(metaClass, metaProperty));
} else {
return null;
}
}
@Override
public Collection getItemPropertyIds() {
return properties.keySet();
}
@Override
public boolean addItemProperty(Object id, Property property) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeItemProperty(Object id) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public void addPropertySetChangeListener(PropertySetChangeListener listener) {
if (listeners == null) {
listeners = new LinkedList<>();
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
@Override
public void addListener(PropertySetChangeListener listener) {
addPropertySetChangeListener(listener);
}
@Override
public void removePropertySetChangeListener(PropertySetChangeListener listener) {
if (listeners != null) {
listeners.remove(listener);
if (listeners.isEmpty()) {
listeners = null;
}
}
}
@Override
public void removeListener(PropertySetChangeListener listener) {
removePropertySetChangeListener(listener);
}
@Override
public void unsubscribe() {
if (item instanceof CollectionContainer) {
CollectionContainer container = (CollectionContainer) item;
// noinspection unchecked
container.removeCollectionChangeListener(weakCollectionChangeListener);
weakCollectionChangeListener = null;
}
item = null;
metaClass = null;
properties.values().forEach(PropertyAdapter::unsubscribe);
properties.clear();
}
private class PropertySetChangeEvent implements Item.PropertySetChangeEvent {
@Override
public Item getItem() {
return ItemAdapter.this;
}
}
@Override
public String toString() {
final Entity entity = getItem();
return entity == null ? "" : entity.getInstanceName();
}
public Entity getItem() {
return item instanceof InstanceContainer ? ((InstanceContainer) item).getItem() : (Entity) item;
}
}

View File

@ -0,0 +1,165 @@
/*
* 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.web.gui.model;
import com.google.common.base.Strings;
import com.haulmont.chile.core.datatypes.Datatype;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.Instance;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.chile.core.model.Range;
import com.haulmont.chile.core.model.utils.InstanceUtils;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.MetadataTools;
import com.haulmont.cuba.core.global.UserSessionSource;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.impl.WeakItemChangeListener;
import com.haulmont.cuba.gui.model.impl.WeakItemPropertyChangeListener;
import com.haulmont.cuba.web.gui.data.AbstractPropertyWrapper;
import com.haulmont.cuba.web.gui.data.UnsubscribableDsWrapper;
import com.haulmont.cuba.web.widgets.data.PropertyValueStringify;
import com.vaadin.v7.data.util.converter.Converter;
import java.text.ParseException;
public class PropertyAdapter extends AbstractPropertyWrapper implements PropertyValueStringify, UnsubscribableDsWrapper {
protected MetaPropertyPath propertyPath;
protected MetadataTools metadataTools = AppBeans.get(MetadataTools.NAME);
protected InstanceContainer.ItemChangeListener dsItemChangeListener;
protected WeakItemChangeListener weakItemChangeListener;
protected InstanceContainer.ItemPropertyChangeListener dsItemPropertyChangeListener;
protected WeakItemPropertyChangeListener weakItemPropertyChangeListener;
public PropertyAdapter(Object item, MetaPropertyPath propertyPath) {
this.item = item;
this.propertyPath = propertyPath;
if (item instanceof InstanceContainer) {
dsItemChangeListener = e -> fireValueChangeEvent();
dsItemPropertyChangeListener = e -> {
if (e.getProperty().equals(this.propertyPath.toString())) {
fireValueChangeEvent();
}
};
InstanceContainer datasource = (InstanceContainer) item;
weakItemChangeListener = new WeakItemChangeListener(datasource, dsItemChangeListener);
//noinspection unchecked
datasource.addItemChangeListener(weakItemChangeListener);
weakItemPropertyChangeListener = new WeakItemPropertyChangeListener(datasource, dsItemPropertyChangeListener);
//noinspection unchecked
datasource.addItemPropertyChangeListener(weakItemPropertyChangeListener);
}
}
@Override
public Object getValue() {
final Instance instance = getInstance();
return instance == null ? null : InstanceUtils.getValueEx(instance, propertyPath.getPath());
}
protected Instance getInstance() {
if (item instanceof InstanceContainer) {
return ((InstanceContainer) item).getItem();
} else {
return (Instance) item;
}
}
@Override
public void setValue(Object newValue) throws ReadOnlyException, Converter.ConversionException {
final Instance instance = getInstance();
if (instance != null) {
InstanceUtils.setValueEx(instance, propertyPath.getPath(), valueOf(newValue));
}
}
protected Object valueOf(Object newValue) throws Converter.ConversionException {
if (newValue == null) {
return null;
}
final Range range = propertyPath.getRange();
if (range == null) {
return newValue;
} else {
final Object obj;
if (range.isDatatype()) {
Datatype<Object> datatype = range.asDatatype();
if (newValue instanceof String) {
try {
newValue = Strings.emptyToNull((String) newValue);
UserSessionSource sessionSource = AppBeans.get(UserSessionSource.NAME);
obj = datatype.parse((String) newValue, sessionSource.getLocale());
} catch (ParseException e) {
throw new Converter.ConversionException(e);
}
} else {
if (newValue.getClass().equals(datatype.getJavaClass())) {
return newValue;
} else {
Datatype newValueDatatype = Datatypes.getNN(newValue.getClass());
//noinspection unchecked
String str = newValueDatatype.format(newValue);
try {
obj = datatype.parse(str);
} catch (ParseException e) {
throw new Converter.ConversionException(e);
}
}
}
} else {
obj = newValue;
}
return obj;
}
}
@Override
public Class getType() {
return propertyPath.getRangeJavaClass();
}
@Override
public String getFormattedValue() {
return metadataTools.format(getValue(), propertyPath.getMetaProperty());
}
@SuppressWarnings("unchecked")
@Override
public void unsubscribe() {
InstanceContainer container = (InstanceContainer) item;
container.removeItemChangeListener(weakItemChangeListener);
weakItemChangeListener = null;
container.removeItemPropertyChangeListener(weakItemPropertyChangeListener);
weakItemPropertyChangeListener = null;
propertyPath = null;
}
@Override
public void fireValueChangeEvent() {
super.fireValueChangeEvent();
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.web.tmp;
import com.haulmont.cuba.gui.components.AbstractWindow;
import com.haulmont.cuba.gui.components.TextField;
import com.haulmont.cuba.gui.model.DataContextFactory;
import com.haulmont.cuba.gui.model.InstanceContainer;
import com.haulmont.cuba.gui.model.InstanceLoader;
import com.haulmont.cuba.security.entity.User;
import javax.inject.Inject;
import java.util.Map;
import java.util.UUID;
/**
*
*/
public class DcScreen1 extends AbstractWindow {
@Inject
private TextField textField1;
@Inject
private TextField textField2;
@Inject
private DataContextFactory dataContextFactory;
private InstanceContainer<User> container;
@Override
public void init(Map<String, Object> params) {
container = dataContextFactory.createInstanceContainer(User.class);
textField1.setContainer(container, "name");
textField2.setContainer(container, "name");
InstanceLoader<User, UUID> loader = dataContextFactory.createInstanceLoader();
loader.setContainer(container);
loader.setEntityId(UUID.fromString("60885987-1b61-4247-94c7-dff348347f93"));
loader.load();
}
public void changeName() {
container.getItemNN().setName("User-" + System.currentTimeMillis());
}
}

View File

@ -0,0 +1,152 @@
/*
* 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.web.tmp;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.components.AbstractWindow;
import com.haulmont.cuba.gui.components.Table;
import com.haulmont.cuba.gui.components.TextField;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.model.DataContext;
import com.haulmont.cuba.gui.model.DataContextFactory;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.security.entity.Group;
import com.haulmont.cuba.security.entity.User;
import javax.inject.Inject;
import java.util.*;
import java.util.stream.Collectors;
/**
*
*/
public class DcScreen2 extends AbstractWindow {
@Inject
private TextField textField1;
@Inject
private Metadata metadata;
@Inject
private DataContextFactory dataContextFactory;
@Inject
private ComponentsFactory componentsFactory;
@Inject
private DataManager dataManager;
private List<User> users;
private int index;
private CollectionContainer<User> container;
private boolean reverse;
private boolean filter;
private Table<User> table;
private CollectionLoader<User> loader;
private DataContext dataContext;
@Override
public void init(Map<String, Object> params) {
dataContext = dataContextFactory.createDataContext();
table = componentsFactory.createComponent(Table.class);
table.setWidthFull();
add(table);
expand(table);
MetaClass metaClass = metadata.getClassNN(User.class);
table.addColumn(new Table.Column(metaClass.getPropertyPath("login")));
table.addColumn(new Table.Column(metaClass.getPropertyPath("name")));
container = dataContextFactory.createCollectionContainer(User.class);
loader = dataContextFactory.createCollectionLoader();
loader.setDataContext(dataContext);
loader.setContainer(container);
loader.setQuery("select u from sec$User u order by u.name");
loader.setView(View.LOCAL);
loader.load();
// users = dataManager.loadList(LoadContext.create(User.class)
// .setQuery(LoadContext.createQuery("select u from sec$User u order by u.name"))
// .setView(View.LOCAL));
// container.setItems(users);
table.setContainer(container);
textField1.setContainer(container, "name");
}
public void sort() {
reverse = !reverse;
List<User> items = new ArrayList<>(container.getItems());
items.sort(Comparator.nullsLast(Comparator.comparing(User::getName)));
if (reverse)
Collections.reverse(items);
container.setItems(items);
}
public void filter() {
filter = !filter;
if (!filter) {
loader.load();
} else {
List<User> items = container.getItems().stream()
.filter(user -> user.getLogin().startsWith("u"))
.collect(Collectors.toList());
container.setItems(items);
}
}
public void nextUser() {
index = container.getItems().indexOf(container.getItem());
index++;
if (index > users.size() - 1)
index = 0;
container.setItem(users.get(index));
}
public void addUser() {
Group group = dataManager.load(LoadContext.create(Group.class).setId(UUID.fromString("0fa2b1a5-1d68-4d69-9fbd-dff348347f93")));
User user = metadata.create(User.class);
long millis = System.currentTimeMillis();
user.setLogin("u-" + millis);
user.setName("User-" + millis);
user.setGroup(group);
user = dataContext.merge(user);
container.getMutableItems().add(user);
table.setSelected(user);
}
public void removeUser() {
User user = container.getItem();
if (user != null) {
container.getMutableItems().remove(user);
dataContext.remove(user);
}
}
public void saveChanges() {
dataContext.commit();
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.web.tmp;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.components.AbstractWindow;
import com.haulmont.cuba.gui.components.SplitPanel;
import com.haulmont.cuba.gui.components.Table;
import com.haulmont.cuba.gui.components.TextField;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.model.CollectionLoader;
import com.haulmont.cuba.gui.model.DataContextFactory;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.entity.UserRole;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
/**
*
*/
public class DcScreen3 extends AbstractWindow {
@Inject
private TextField textField1;
@Inject
private SplitPanel split;
@Inject
private Metadata metadata;
@Inject
private DataContextFactory dataContextFactory;
@Inject
private ComponentsFactory componentsFactory;
private CollectionContainer<User> usersContainer;
private CollectionContainer<UserRole> userRolesContainer;
@Override
public void init(Map<String, Object> params) {
Table usersTable = componentsFactory.createComponent(Table.class);
usersTable.setSizeFull();
split.add(usersTable);
Table userRolesTable = componentsFactory.createComponent(Table.class);
userRolesTable.setSizeFull();
split.add(userRolesTable);
MetaClass userMetaClass = metadata.getClassNN(User.class);
usersTable.addColumn(new Table.Column(userMetaClass.getPropertyPath("login")));
usersTable.addColumn(new Table.Column(userMetaClass.getPropertyPath("name")));
MetaClass userRoleMetaClass = metadata.getClassNN(UserRole.class);
userRolesTable.addColumn(new Table.Column(userRoleMetaClass.getPropertyPath("role.name")));
usersContainer = dataContextFactory.createCollectionContainer(User.class);
userRolesContainer = dataContextFactory.createCollectionContainer(UserRole.class);
CollectionLoader<User> loader = dataContextFactory.createCollectionLoader();
loader.setContainer(usersContainer);
loader.setQuery("select u from sec$User u order by u.name");
loader.setView("user.edit");
loader.load();
usersContainer.addItemChangeListener(e -> {
User user = e.getItem();
userRolesContainer.setItems(user != null ? user.getUserRoles() : null);
});
usersTable.setContainer(usersContainer);
userRolesTable.setContainer(userRolesContainer);
textField1.setContainer(usersContainer, "name");
}
}

View File

@ -0,0 +1,14 @@
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
class="com.haulmont.cuba.web.tmp.DcScreen1"
caption="Screen 1"
messagesPack="com.haulmont.cuba.web.tmp">
<dsContext/>
<layout expand="spacer" spacing="true">
<textField id="textField1"/>
<textField id="textField2"/>
<button caption="Change" invoke="changeName"/>
<label id="spacer"/>
</layout>
</window>

View File

@ -0,0 +1,35 @@
<!--
~ 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.
-->
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
class="com.haulmont.cuba.web.tmp.DcScreen2"
caption="Screen 2"
messagesPack="com.haulmont.cuba.web.tmp">
<dsContext/>
<layout spacing="true">
<textField id="textField1"/>
<hbox spacing="true">
<button caption="Next User" invoke="nextUser"/>
<button caption="Sort" invoke="sort"/>
<button caption="Filter" invoke="filter"/>
<button caption="Add User" invoke="addUser"/>
<button caption="Remove User" invoke="removeUser"/>
<button caption="Save Changes" invoke="saveChanges"/>
</hbox>
</layout>
</window>

View File

@ -0,0 +1,33 @@
<!--
~ 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.
-->
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
class="com.haulmont.cuba.web.tmp.DcScreen3"
caption="Screen 3"
messagesPack="com.haulmont.cuba.web.tmp">
<dsContext/>
<layout spacing="true" expand="split">
<textField id="textField1"/>
<split id="split" orientation="horizontal" width="100%">
</split>
<!--<button caption="Change" invoke="changeName"/>-->
<!--<button caption="Next User" invoke="nextUser"/>-->
<!--<label id="spacer"/>-->
</layout>
</window>

View File

@ -18,6 +18,10 @@
<menu-config xmlns="http://schemas.haulmont.com/cuba/menu.xsd">
<menu id="administration">
<item id="dcScreen1"/>
<item id="dcScreen2"/>
<item id="dcScreen3"/>
<separator/>
<item id="sec$User.browse"/>
<item id="sec$Group.browse"/>
<item id="sec$Role.browse"/>

View File

@ -76,4 +76,11 @@
<screen id="loginWindow"
template="/com/haulmont/cuba/web/app/loginwindow/loginwindow.xml"/>
<screen id="dcScreen1"
template="/com/haulmont/cuba/web/tmp/dc-screen-1.xml"/>
<screen id="dcScreen2"
template="/com/haulmont/cuba/web/tmp/dc-screen-2.xml"/>
<screen id="dcScreen3"
template="/com/haulmont/cuba/web/tmp/dc-screen-3.xml"/>
</screen-config>