org.netbeans.modeler.specification.model.document.property.ElementPropertySet.java Source code

Java tutorial

Introduction

Here is the source code for org.netbeans.modeler.specification.model.document.property.ElementPropertySet.java

Source

/**
 * Copyright 2013-2018 Gaurav Gupta
 *
 * 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 org.netbeans.modeler.specification.model.document.property;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.netbeans.modeler.config.element.Attribute;
import org.netbeans.modeler.config.element.Element;
import org.netbeans.modeler.config.element.ElementConfig;
import org.netbeans.modeler.config.element.ElementConfigFactory;
import org.netbeans.modeler.config.element.Group;
import org.netbeans.modeler.config.element.ModelerSheetProperty;
import org.netbeans.modeler.core.ModelerFile;
import org.netbeans.modeler.properties.enumtype.EnumComboBoxResolver;
import org.netbeans.modeler.properties.type.Embedded;
import org.netbeans.modeler.properties.type.Enumy;
import org.netbeans.modeler.specification.model.document.ITextElement;
import static org.netbeans.modeler.specification.model.document.property.PropertySetUtil.createPropertyChangeHandler;
import static org.netbeans.modeler.specification.model.document.property.PropertySetUtil.createPropertyVisibilityHandler;
import static org.netbeans.modeler.specification.model.document.property.PropertySetUtil.elementValueChanged;
import org.netbeans.modeler.specification.model.document.widget.IBaseElementWidget;
import org.netbeans.modeler.widget.properties.generic.ElementCustomPropertySupport;
import org.netbeans.modeler.widget.properties.generic.ElementPropertySupport;
import org.netbeans.modeler.widget.properties.handler.PropertyChangeListener;
import org.netbeans.modeler.widget.properties.handler.PropertyVisibilityHandler;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;

public class ElementPropertySet {

    private ModelerFile modelerFile;
    private final ElementConfig elementConfig;
    private Sheet sheet;
    private Map<Group, Sheet.Set> set = new HashMap<>();

    public ElementPropertySet(ModelerFile modelerFile, Sheet sheet) {
        this.modelerFile = modelerFile;
        this.sheet = sheet;
        this.elementConfig = modelerFile.getModelerDiagramModel().getElementConfigFactory().getElementConfig();
        ;
    }

    public void createGroup(Group group) {
        set.put(group, sheet.createPropertiesSet());
        set.get(group).setName(group.getId());// Sheet.Set : name is required work as key [otherwise set is replaced]
    }

    public void deleteGroup(String id) {
        Group group = getElementConfigGroup(id);
        set.remove(group);
    }

    public void clearGroup(String id) {
        Group group = getElementConfigGroup(id);
        if (set.get(group) != null) {
            for (Node.Property<?> property : set.get(group).getProperties()) {
                set.get(group).remove(property.getName());
            }
        }
    }

    public void clearGroups() {
        for (Sheet.Set setTmp : set.values()) {
            Arrays.fill(setTmp.getProperties(), null);
        }
        set.clear();
    }

    private Map<String, LinkedList<SheetProperty>> preOrderedPropeties = new LinkedHashMap<>();

    public synchronized void put(String id, Node.Property<?> p, boolean replace) {
        LinkedList<SheetProperty> properties = preOrderedPropeties.get(id);
        if (properties == null) {
            preOrderedPropeties.put(id, properties = new LinkedList<>());
        }
        properties.add(new SheetProperty(p, replace));
    }

    public void executeProperties() {
        for (Entry<String, LinkedList<SheetProperty>> entry : preOrderedPropeties.entrySet()) {
            LinkedList<SheetProperty> propertyList = entry.getValue();
            //Prepare hashmap container
            Map<String, PropertyLinkedList<SheetProperty>> filterContainerMap = new LinkedHashMap<>();
            propertyList.forEach(p -> {
                if (filterContainerMap.get(p.getProperty().getName()) == null) {
                    PropertyLinkedList<SheetProperty> propertyLinkedList = new PropertyLinkedList<>();
                    propertyLinkedList.addFirst(p);
                    filterContainerMap.put(p.getProperty().getName(), propertyLinkedList);
                } else {
                    filterContainerMap.get(p.getProperty().getName()).addLast(p);
                }
            });

            propertyList.forEach(p -> {
                if (p.getProperty() instanceof ModelerSheetProperty) {
                    ModelerSheetProperty msp = (ModelerSheetProperty) p.getProperty();
                    if (msp.getAfter() != null) {
                        PropertyLinkedList<SheetProperty> linklistA = filterContainerMap.get(msp.getAfter());
                        PropertyLinkedList<SheetProperty> linklistB = filterContainerMap
                                .get(p.getProperty().getName());
                        if (linklistA == null) {
                            System.out.println("Invalid after type : " + msp.getAfter());
                        }
                        if (linklistA != null && linklistA != linklistB) {
                            linklistA.addLast(linklistB.getHead());
                        }
                    }
                    if (msp.getBefore() != null) {
                        PropertyLinkedList<SheetProperty> linklistB = filterContainerMap
                                .get(p.getProperty().getName());
                        PropertyLinkedList<SheetProperty> linklistA = filterContainerMap.get(msp.getBefore());
                        if (linklistA == null) {
                            System.out.println("Invalid before type : " + msp.getBefore());
                        }
                        if (linklistA != null && linklistA != linklistB) {
                            linklistB.addLast(linklistA.getHead());
                        }
                    }
                }
            });

            for (Entry<String, PropertyLinkedList<SheetProperty>> filterEntry : filterContainerMap.entrySet()) {
                PropertyLinkedList<SheetProperty> propertyLinkedList = filterEntry.getValue();
                if (propertyLinkedList.getHead().prev == null) {
                    PropertyLinkedList<SheetProperty>.Node node = propertyLinkedList.getHead();
                    while (node != null) {
                        putProperty(entry.getKey(), node.element.getProperty(), node.element.isReplace());
                        node = node.next;
                    }
                }
            }

        }
        preOrderedPropeties.clear();
    }

    public synchronized Node.Property<?> putProperty(String id, Node.Property<?> p, boolean replace) {
        Group group = getElementConfigGroup(id);
        if (set.get(group) == null) {
            createGroup(group);
            setGroupDisplayName(id, group.getName());
        }
        if (replace && set.get(group).get(p.getName()) != null) {
            set.get(group).remove(p.getName());
        }
        return set.get(group).put(p);
    }

    private Group getElementConfigGroup(String id) {
        Group group = elementConfig.getGroup(id);
        if (group == null) {
            throw new RuntimeException("Group Id : <" + id + "> not found in element config");
        }
        return group;
    }

    public synchronized void put(String id, Node.Property<?> p) {
        put(id, p, false);
    }

    public void setGroupDisplayName(String id, String displayName) {
        Group group = getElementConfigGroup(id);
        set.get(group).setDisplayName(displayName);
    }

    /**
     * @return the sheet
     */
    public Sheet getSheet() {
        return sheet;
    }

    /**
     * @param sheet the sheet to set
     */
    public void setSheet(Sheet sheet) {
        this.sheet = sheet;
    }

    /**
     * @return the set
     */
    public Sheet.Set getGroup(String id) {
        Group group = getElementConfigGroup(id);
        return set.get(group);
    }

    public Set<String> getGroupKey() {
        return set.keySet().stream().map(Group::getName).collect(toSet());
    }

    public List<Sheet.Set> getGroups() {
        return set.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(entry -> entry.getValue())
                .collect(toList());
    }

    /**
     * @return the modelerFile
     */
    public ModelerFile getModelerFile() {
        return modelerFile;
    }

    /**
     * @param modelerFile the modelerFile to set
     */
    public void setModelerFile(ModelerFile modelerFile) {
        this.modelerFile = modelerFile;
    }

    public void createPropertySet(IBaseElementWidget baseElementWidget, final Object object) {
        createPropertySet(null, null, baseElementWidget, object, null, null, true, false);
    }

    public void createPropertySet(IBaseElementWidget baseElementWidget, final Object object,
            final Map<String, PropertyChangeListener> propertyChangeHandlers) {
        createPropertySet(null, null, baseElementWidget, object, propertyChangeHandlers, null, true, false);
    }

    /*
    * Override attributes groupId
    */
    public void createPropertySet(String groupId, IBaseElementWidget baseElementWidget, final Object object,
            final Map<String, PropertyChangeListener> propertyChangeHandlers) {
        createPropertySet(groupId, null, baseElementWidget, object, propertyChangeHandlers, null, true, false);
    }

    /*
    * Filter using category
      category used when object have more than one child of same type
    */
    public void createPropertySet(String groupId, String category, IBaseElementWidget baseElementWidget,
            final Object object) {
        createPropertySet(groupId, category, baseElementWidget, object, null, null, true, false);
    }

    public void createPropertySet(String groupId, String category, IBaseElementWidget baseElementWidget,
            final Object object, final Map<String, PropertyChangeListener> propertyChangeHandlers) {
        createPropertySet(groupId, category, baseElementWidget, object, propertyChangeHandlers, null, true, false);
    }

    public void createPropertySet(IBaseElementWidget baseElementWidget, final Object object,
            final Map<String, PropertyChangeListener> propertyChangeHandlers,
            final Map<String, PropertyVisibilityHandler> propertyVisiblityHandlers) {
        createPropertySet(null, null, baseElementWidget, object, propertyChangeHandlers, propertyVisiblityHandlers,
                true, false);
    }

    public void createPropertySet(IBaseElementWidget baseElementWidget, final Object object,
            final Map<String, PropertyChangeListener> propertyChangeHandlers, boolean inherit) {
        createPropertySet(null, null, baseElementWidget, object, propertyChangeHandlers, null, true, false);
    }

    /**
     * Replace Property Start
     *
     * @param baseElementWidget
     * @param object
     * @param propertyChangeHandlers *
     */
    public void replacePropertySet(IBaseElementWidget baseElementWidget, final Object object,
            final Map<String, PropertyChangeListener> propertyChangeHandlers) {
        createPropertySet(null, null, baseElementWidget, object, propertyChangeHandlers, null, true, true);
    }

    private void createPropertySet(String groupId, String category, IBaseElementWidget baseElementWidget,
            final Object object, final Map<String, PropertyChangeListener> propertyChangeHandlers,
            final Map<String, PropertyVisibilityHandler> propertyVisiblityHandlers, boolean inherit,
            boolean replaceProperty) {
        ElementConfigFactory elementConfigFactory = modelerFile.getModelerDiagramModel().getElementConfigFactory();
        if (inherit) {
            for (Element element : elementConfigFactory.getElements(category, object.getClass())) {
                createPropertySetInternal(groupId, baseElementWidget, object, element, propertyChangeHandlers,
                        propertyVisiblityHandlers, replaceProperty);
            }
        } else {
            Element element = elementConfigFactory.getElement(category, object.getClass());
            if (element != null) {
                createPropertySetInternal(groupId, baseElementWidget, object, element, propertyChangeHandlers,
                        propertyVisiblityHandlers, replaceProperty);
            }
        }
    }

    private void createPropertySetInternal(String groupId, final IBaseElementWidget baseElementWidget,
            final Object object, Element element, final Map<String, PropertyChangeListener> propertyChangeHandlers,
            final Map<String, PropertyVisibilityHandler> propertyVisiblityHandlers, boolean replaceProperty) {
        try {
            if (element != null) {
                for (final Attribute attribute : element.getAttributes()) {
                    String attributeGroupId = groupId;
                    if (attributeGroupId == null) {
                        attributeGroupId = attribute.getGroupId();
                    }
                    if (attribute.getClassType() == ITextElement.class) {
                        final String name = attribute.getName();
                        final ITextElement expression = (ITextElement) PropertyUtils.getProperty(object, name);//return must not be null//(TExpression) PropertyUtils.getProperty(object, id) == null ? new TExpression() : (TExpression) PropertyUtils.getProperty(object, id);
                        this.put(attributeGroupId,
                                new ElementCustomPropertySupport(this.getModelerFile(), expression, String.class,
                                        attribute.getId(), "content", attribute.getDisplayName(),
                                        attribute.getShortDescription(),
                                        (PropertyChangeListener<String>) (oldValue, value) -> {
                                            if (expression.getContent() == null
                                                    || expression.getContent().isEmpty()) {
                                                try {
                                                    PropertyUtils.setProperty(object, name, null);
                                                } catch (IllegalAccessException | InvocationTargetException
                                                        | NoSuchMethodException ex) {
                                                    Exceptions.printStackTrace(ex);
                                                }
                                            }
                                            if (propertyChangeHandlers != null
                                                    && propertyChangeHandlers.get(name) != null) {
                                                propertyChangeHandlers.get(name).changePerformed(oldValue, value);
                                            }
                                            if (attribute.isRefreshOnChange()) {
                                                baseElementWidget.refreshProperties();
                                            }
                                        },
                                        propertyVisiblityHandlers == null ? null
                                                : propertyVisiblityHandlers.get(attribute.getId())),
                                replaceProperty);

                    } else if (Enumy.class.isAssignableFrom(attribute.getClassType())) {
                        EnumComboBoxResolver resolver = Lookup.getDefault().lookup(EnumComboBoxResolver.class);
                        this.put(attributeGroupId, resolver.getPropertySupport(modelerFile, attribute,
                                baseElementWidget, object, propertyChangeHandlers));
                    } else if (Embedded.class.isAssignableFrom(attribute.getClassType())) {
                        if (attribute.getGroupId() != null) {
                            groupId = attribute.getGroupId();
                        }
                        //in embedded id is used as category
                        this.createPropertySet(groupId, attribute.getId(), baseElementWidget,
                                PropertyUtils.getSimpleProperty(object, attribute.getName()),
                                propertyChangeHandlers, propertyVisiblityHandlers, true, replaceProperty);
                    } else {
                        if (attribute.isReadOnly()) {
                            String value = BeanUtils.getProperty(object, attribute.getName());
                            if (value == null) {
                                BeanUtils.setProperty(object, attribute.getName(), attribute.getValue());
                            }
                            this.put(attributeGroupId,
                                    new ElementPropertySupport(object, attribute.getFieldGetter(), null, attribute),
                                    replaceProperty);
                        } else {
                            PropertyVisibilityHandler propertyVisibilityHandler = propertyVisiblityHandlers == null
                                    ? null
                                    : propertyVisiblityHandlers.get(attribute.getId());

                            Serializable visibilityExpression = attribute.getVisibilityExpression();
                            if (propertyVisibilityHandler == null && visibilityExpression != null) {
                                propertyVisibilityHandler = createPropertyVisibilityHandler(modelerFile,
                                        baseElementWidget, object, visibilityExpression);
                            }
                            if (propertyChangeHandlers != null
                                    && propertyChangeHandlers.get(attribute.getId()) == null
                                    && attribute.getOnChangeEvent() != null
                                    && !attribute.getOnChangeEvent().trim().isEmpty()) {
                                propertyChangeHandlers.put(attribute.getId(),
                                        createPropertyChangeHandler(modelerFile, baseElementWidget, object,
                                                attribute.getChangeListenerExpression()));
                            }
                            this.put(attributeGroupId, new ElementCustomPropertySupport(this.getModelerFile(),
                                    object, attribute, (PropertyChangeListener<Object>) (oldValue, value) -> {
                                        try {
                                            if (value != null) {
                                                if (value instanceof String) {
                                                    if (!((String) value).isEmpty()) {
                                                        BeanUtils.setProperty(object, attribute.getName(), value);
                                                    } else {
                                                        BeanUtils.setProperty(object, attribute.getName(), null);
                                                    }
                                                } else {
                                                    BeanUtils.setProperty(object, attribute.getName(), value);
                                                }
                                            } else {
                                                BeanUtils.setProperty(object, attribute.getName(), null);
                                            }
                                        } catch (IllegalAccessException | InvocationTargetException ex) {
                                            Exceptions.printStackTrace(ex);
                                        }
                                        elementValueChanged(baseElementWidget, attribute, propertyChangeHandlers,
                                                oldValue, value);
                                    }, propertyVisibilityHandler), replaceProperty);

                        }
                    }
                }
            }
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException
                | NoSuchFieldException ex) {
            Exceptions.printStackTrace(ex);
        }

    }

}

class SheetProperty {
    private Node.Property<?> property;
    private boolean replace;

    public SheetProperty(Node.Property<?> property) {
        this.property = property;
    }

    public SheetProperty(Node.Property<?> property, boolean replace) {
        this.property = property;
        this.replace = replace;
    }

    /**
     * @return the property
     */
    public Node.Property<?> getProperty() {
        return property;
    }

    /**
     * @param property the property to set
     */
    public void setProperty(Node.Property<?> property) {
        this.property = property;
    }

    /**
     * @return the replace
     */
    public boolean isReplace() {
        return replace;
    }

    /**
     * @param replace the replace to set
     */
    public void setReplace(boolean replace) {
        this.replace = replace;
    }
}