org.jumpmind.metl.ui.views.design.EditSorterPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.metl.ui.views.design.EditSorterPanel.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * 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.jumpmind.metl.ui.views.design;

import static org.apache.commons.lang.StringUtils.isBlank;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.metl.core.model.ComponentAttributeSetting;
import org.jumpmind.metl.core.model.ComponentEntitySetting;
import org.jumpmind.metl.core.model.Model;
import org.jumpmind.metl.core.model.ModelAttribute;
import org.jumpmind.metl.core.model.ModelEntity;
import org.jumpmind.metl.core.runtime.component.Sorter;
import org.jumpmind.metl.ui.common.ButtonBar;

import com.vaadin.data.Container;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.event.Transferable;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptAll;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.server.FontAwesome;
import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Field;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.CellStyleGenerator;
import com.vaadin.ui.TableFieldFactory;
import com.vaadin.ui.TextField;

@SuppressWarnings("serial")
public class EditSorterPanel extends AbstractComponentEditPanel {

    Table table = new Table();

    BeanItemContainer<RecordFormat> container = new BeanItemContainer<RecordFormat>(RecordFormat.class);

    TextField filterTextField;

    Set<RecordFormat> selectedItemIds;

    static final String SHOW_ALL = "Show All Entities";
    static final String SHOW_POPULATED_ENTITIES = "Filter Populated Entites";

    protected void buildUI() {
        ButtonBar buttonBar = new ButtonBar();
        addComponent(buttonBar);

        Button moveUpButton = buttonBar.addButton("Move Up", FontAwesome.ARROW_UP);
        moveUpButton.addClickListener(new MoveUpClickListener());

        Button moveDownButton = buttonBar.addButton("Move Down", FontAwesome.ARROW_DOWN);
        moveDownButton.addClickListener(new MoveDownClickListener());

        Button moveTopButton = buttonBar.addButton("Move Top", FontAwesome.ANGLE_DOUBLE_UP);
        moveTopButton.addClickListener(new MoveTopClickListener());

        Button moveBottomButton = buttonBar.addButton("Move Bottom", FontAwesome.ANGLE_DOUBLE_DOWN);
        moveBottomButton.addClickListener(new MoveBottomClickListener());

        filterTextField = buttonBar.addFilter();
        filterTextField.addTextChangeListener(event -> updateTable(event.getText()));

        table.setContainerDataSource(container);

        table.setSelectable(true);
        table.setSortEnabled(false);
        table.setImmediate(true);
        table.setSizeFull();
        table.setVisibleColumns(new Object[] { "entityName", "attributeName", "ordinalSetting", "sortSetting" });
        table.setColumnHeaders(new String[] { "Entity Name", "Attribute Name", "Sort Order", "Sort" });
        table.setTableFieldFactory(new EditFieldFactory());
        table.setCellStyleGenerator(new TableCellStyleGenerator());
        table.setEditable(true);
        table.setMultiSelect(true);
        addComponent(table);
        setExpandRatio(table, 1.0f);

        updateTable(null);

        calculatePositions();
        saveOrdinalSettings();
        saveSortSettings();
    }

    @SuppressWarnings("unchecked")
    protected Set<RecordFormat> getSelectedItems() {
        return (Set<RecordFormat>) table.getValue();
    }

    protected RecordFormat getSelectedItem() {
        Set<RecordFormat> selectedItems = getSelectedItems();
        if (selectedItems != null && selectedItems.size() == 1) {
            return selectedItems.iterator().next();
        }
        return null;
    }

    protected void updateTable(String filter) {
        filter = filter != null ? filter.toLowerCase() : null;
        filterTextField.setValue(filter);
        table.removeAllItems();
        Model model = component.getInputModel();

        if (model != null) {
            model = context.getConfigurationService().findModel(model.getId());
            List<RecordFormat> checkedAttributes = new ArrayList<RecordFormat>();
            List<RecordFormat> attributes = new ArrayList<RecordFormat>();

            for (ModelEntity entity : model.getModelEntities()) {
                if (isBlank(filter) || entity.getName().toLowerCase().contains(filter)) {
                    for (ModelAttribute attr : entity.getModelAttributes()) {
                        RecordFormat recFormat = new RecordFormat(entity, attr);
                        if (recFormat.getSortSetting()) {
                            checkedAttributes.add(recFormat);
                        } else {
                            attributes.add(recFormat);
                        }
                    }
                }
            }

            Collections.sort(attributes, new Comparator<RecordFormat>() {
                public int compare(RecordFormat o1, RecordFormat o2) {
                    return new String(o1.getEntityName()).compareTo(new String(o2.getEntityName()));
                }
            });

            Collections.sort(checkedAttributes, new Comparator<RecordFormat>() {
                public int compare(RecordFormat o1, RecordFormat o2) {
                    int sortOrder = new String(o1.getEntityName()).compareTo(new String(o2.getEntityName()));

                    if (sortOrder != 0) {
                        return sortOrder;
                    } else {
                        return new Integer(o1.getOrdinalSetting() == 0 ? 999999 : o1.getOrdinalSetting()).compareTo(
                                new Integer(o2.getOrdinalSetting() == 0 ? 999999 : o2.getOrdinalSetting()));
                    }
                }
            });

            for (RecordFormat recordFormat : checkedAttributes) {
                table.addItem(recordFormat);
            }

            for (RecordFormat recordFormat : attributes) {
                table.addItem(recordFormat);
            }
        }
    }

    protected void calculatePositions() {
        boolean needsRefreshed = false;
        int ordinal = 1;
        for (RecordFormat record : container.getItemIds()) {
            if (record.getSortSetting()) {
                if (record.getOrdinalSetting() != ordinal) {
                    record.setOrdinalSetting(ordinal);
                    needsRefreshed = true;
                }
                ordinal++;
            } else {
                if (record.getOrdinalSetting() != 0) {
                    record.setOrdinalSetting(0);
                    needsRefreshed = true;
                }
            }
        }

        if (needsRefreshed) {
            RecordFormat record = getSelectedItem();
            if (record != null) {
                record.setFocusFieldId("sortSetting");
            }
            table.refreshRowCache();
        }
    }

    protected void moveItemsTo(Set<RecordFormat> itemIds, int index) {
        if (index >= 0 && index < container.getItemIds().size() && itemIds.size() > 0) {
            int firstItemIndex = container.indexOfId(itemIds.iterator().next());
            if (index != firstItemIndex) {
                for (RecordFormat itemId : itemIds) {
                    boolean movingUp = index < container.indexOfId(itemId);
                    container.removeItem(itemId);
                    container.addItemAt(index, itemId);
                    if (movingUp) {
                        index++;
                    }
                }
                calculatePositions();
                saveOrdinalSettings();
            }
            table.refreshRowCache();
        }
    }

    protected void saveOrdinalSettings() {
        String attrName = Sorter.SORTER_ATTRIBUTE_ORDINAL;
        int ordinal = 1;
        for (RecordFormat record : container.getItemIds()) {
            if (record.getSortSetting()) {
                saveSetting(record.getAttributeId(), attrName, String.valueOf(ordinal));
                ordinal++;
            } else {
                saveSetting(record.getAttributeId(), attrName, "0");
            }
        }
    }

    protected void saveSortSettings() {
        String attrName = Sorter.ATTRIBUTE_SORTER_ENABLED;

        for (RecordFormat record : container.getItemIds()) {
            saveSetting(record.getAttributeId(), attrName, String.valueOf(record.getSortSetting()));
        }
    }

    protected void saveSetting(String attributeId, String name, String value) {
        ComponentAttributeSetting setting = component.getSingleAttributeSetting(attributeId, name);
        if (setting == null) {
            setting = new ComponentAttributeSetting(attributeId, name, value);
            setting.setComponentId(component.getId());
            component.addAttributeSetting(setting);
            context.getConfigurationService().save(setting);
        } else if (!StringUtils.equals(setting.getValue(), value)) {
            setting.setValue(value);
            context.getConfigurationService().save(setting);
        }
    }

    protected int getLastSortItemIndex(String entityId, String attributeId, boolean isSelected) {
        int lastSortItemIndex = -1;
        int lastEntitySortIndex = -1;
        int lastItemIndex = -1;
        int lastEntityIndex = -1;
        for (RecordFormat record : container.getItemIds()) {
            if (isSelected && record.getSortSetting() && !attributeId.equals(record.getAttributeId())) {
                lastSortItemIndex++;
                if (entityId.equals(record.getEntityId())) {
                    lastEntitySortIndex = container.indexOfId(record);
                }
            }
            lastItemIndex++;
            if (!record.getSortSetting() && entityId.equals(record.getEntityId())
                    && !attributeId.equals(record.getAttributeId())) {
                lastEntityIndex = container.indexOfId(record);
            }
        }

        if (isSelected) {
            if (lastEntitySortIndex < lastSortItemIndex && lastEntitySortIndex != -1) {
                return lastEntitySortIndex;
            } else {
                return lastSortItemIndex;
            }
        } else {
            if (lastEntityIndex < lastItemIndex && lastEntityIndex != -1) {
                return lastEntityIndex;
            } else {
                return lastItemIndex;
            }
        }
    }

    class MoveUpClickListener implements ClickListener {
        public void buttonClick(ClickEvent event) {
            Set<RecordFormat> selectedSortRecords = new HashSet<RecordFormat>();
            int previousEntityLastIndex = -1;
            String selectedEntityId = "";
            for (RecordFormat record : getSelectedItems()) {
                if (record.getSortSetting()) {
                    selectedSortRecords.add(record);
                    if (selectedEntityId == "") {
                        selectedEntityId = record.getEntityId();
                    } else if (!selectedEntityId.equals(record.getEntityId())) {
                        // if an additional selected attribute is from a different entity then don't move anything
                        // can only move within one entity at a time
                        selectedSortRecords.clear();
                        break;
                    }
                }
            }

            if (selectedSortRecords.size() > 0 && selectedSortRecords != null) {
                // loop through list of selected records to see if moving an attribute into another entity
                // add the remaining attributes to keep the entity as a whole together o/w just move the attribute within the entity
                for (RecordFormat record : container.getItemIds()) {
                    if (record.getSortSetting()) {
                        if (!selectedEntityId.equals(record.getEntityId())) {
                            previousEntityLastIndex = container.indexOfId(record);
                        } else {
                            break;
                        }
                    }
                }

                RecordFormat firstItem = selectedSortRecords.iterator().next();
                int index = container.indexOfId(firstItem) - 1;
                if (index >= 0 && index > previousEntityLastIndex) {
                    moveItemsTo(selectedSortRecords, index);
                }
            }
        }
    }

    class MoveDownClickListener implements ClickListener {
        public void buttonClick(ClickEvent event) {
            Set<RecordFormat> selectedSortRecords = new HashSet<RecordFormat>();
            int nextEntityFirstIndex = -1;
            String selectedEntityId = "";
            for (RecordFormat record : getSelectedItems()) {
                if (record.getSortSetting()) {
                    selectedSortRecords.add(record);
                    if (selectedEntityId == "") {
                        selectedEntityId = record.getEntityId();
                    } else if (!selectedEntityId.equals(record.getEntityId())) {
                        // if an additional selected attribute is from a different entity then don't move anything
                        // can only move within one entity at a time
                        selectedSortRecords.clear();
                        break;
                    }
                }
            }

            if (selectedSortRecords.size() > 0 && selectedSortRecords != null) {
                int lastSortItemIndex = 0;
                for (RecordFormat record : container.getItemIds()) {
                    if (record.getSortSetting()) {
                        lastSortItemIndex++;
                    }
                }

                // loop through list of selected records to see if moving an attribute into another entity
                // add the remaining attributes to keep the entity as a whole together o/w just move the attribute within the entity
                ListIterator<RecordFormat> allItemsIterator = container.getItemIds()
                        .listIterator(container.getItemIds().size());
                while (allItemsIterator.hasPrevious()) {
                    RecordFormat record = allItemsIterator.previous();
                    if (record.getSortSetting()) {
                        if (!selectedEntityId.equals(record.getEntityId())) {
                            nextEntityFirstIndex = container.indexOfId(record);
                        } else {
                            break;
                        }
                    }
                }

                RecordFormat lastSortItem = null;
                Iterator<RecordFormat> iter = selectedSortRecords.iterator();
                while (iter.hasNext()) {
                    lastSortItem = iter.next();
                }

                int index = container.indexOfId(lastSortItem) + 1;
                if (index < lastSortItemIndex && (index < nextEntityFirstIndex || nextEntityFirstIndex == -1)) {
                    moveItemsTo(selectedSortRecords, index);
                }
            }
        }
    }

    class MoveTopClickListener implements ClickListener {
        public void buttonClick(ClickEvent event) {
            Set<RecordFormat> selectedSortRecords = new HashSet<RecordFormat>();
            int previousEntityLastIndex = -1;
            String selectedEntityId = "";
            for (RecordFormat record : getSelectedItems()) {
                if (record.getSortSetting()) {
                    selectedSortRecords.add(record);
                    if (selectedEntityId == "") {
                        selectedEntityId = record.getEntityId();
                    } else if (!selectedEntityId.equals(record.getEntityId())) {
                        // if an additional selected attribute is from a different entity then don't move anything
                        // can only move within one entity at a time
                        selectedSortRecords.clear();
                        break;
                    }
                }
            }

            if (selectedSortRecords.size() > 0 && selectedSortRecords != null) {
                // loop through list of selected records to see if moving an attribute into another entity
                // add the remaining attributes to keep the entity as a whole together o/w just move the attribute within the entity
                for (RecordFormat record : container.getItemIds()) {
                    if (record.getSortSetting()) {
                        if (!selectedEntityId.equals(record.getEntityId())) {
                            previousEntityLastIndex = container.indexOfId(record);
                        } else {
                            break;
                        }
                    }
                }

                if (previousEntityLastIndex == -1) {
                    moveItemsTo(selectedSortRecords, 0);
                } else {
                    moveItemsTo(selectedSortRecords, previousEntityLastIndex + 1);
                }
            }
        }
    }

    class MoveBottomClickListener implements ClickListener {
        public void buttonClick(ClickEvent event) {
            Set<RecordFormat> selectedSortRecords = new HashSet<RecordFormat>();
            int nextEntityFirstIndex = -1;
            String selectedEntityId = "";
            for (RecordFormat record : getSelectedItems()) {
                if (record.getSortSetting()) {
                    selectedSortRecords.add(record);
                    if (selectedEntityId == "") {
                        selectedEntityId = record.getEntityId();
                    } else if (!selectedEntityId.equals(record.getEntityId())) {
                        // if an additional selected attribute is from a different entity then don't move anything
                        // can only move within one entity at a time
                        selectedSortRecords.clear();
                        break;
                    }
                }
            }

            if (selectedSortRecords.size() > 0 && selectedSortRecords != null) {
                // loop through list of selected records to see if moving an attribute into another entity
                // add the remaining attributes to keep the entity as a whole together o/w just move the attribute within the entity
                ListIterator<RecordFormat> allItemsIterator = container.getItemIds()
                        .listIterator(container.getItemIds().size());
                while (allItemsIterator.hasPrevious()) {
                    RecordFormat record = allItemsIterator.previous();
                    if (record.getSortSetting()) {
                        if (!selectedEntityId.equals(record.getEntityId())) {
                            nextEntityFirstIndex = container.indexOfId(record);
                        } else {
                            break;
                        }
                    }
                }

                RecordFormat lastSortItem = null;
                for (RecordFormat record : container.getItemIds()) {
                    if (record.getSortSetting()) {
                        lastSortItem = record;
                    }
                }

                if (nextEntityFirstIndex == -1) {
                    int index = container.indexOfId(lastSortItem);
                    moveItemsTo(selectedSortRecords, index);
                } else {
                    moveItemsTo(selectedSortRecords, nextEntityFirstIndex - 1);
                }
            }
        }
    }

    class TableDropHandler implements DropHandler {
        public void drop(DragAndDropEvent event) {
            AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event.getTargetDetails();
            Transferable transferable = event.getTransferable();
            if (transferable.getSourceComponent() == table) {
                RecordFormat target = (RecordFormat) targetDetails.getItemIdOver();
                moveItemsTo(getSelectedItems(), container.indexOfId(target));
            }
        }

        public AcceptCriterion getAcceptCriterion() {
            return AcceptAll.get();
        }
    }

    class EditFieldFactory implements TableFieldFactory {
        public Field<?> createField(final Container dataContainer, final Object itemId, final Object propertyId,
                com.vaadin.ui.Component uiContext) {
            final RecordFormat record = (RecordFormat) itemId;
            Field<?> field = null;
            if (propertyId.equals("sortSetting")) {
                return createAttributeCheckBox(record, Sorter.ATTRIBUTE_SORTER_ENABLED);
            }

            RecordFormat selected = getSelectedItem();
            if (selected == itemId && record.getFocusField() != null) {
                record.getFocusField().focus();
            }
            return field;
        }

        protected CheckBox createAttributeCheckBox(final RecordFormat record, final String key) {
            final CheckBox checkBox = new CheckBox();
            checkBox.setImmediate(true);
            checkBox.addValueChangeListener(new ValueChangeListener() {
                private static final long serialVersionUID = 1L;

                @Override
                public void valueChange(ValueChangeEvent event) {
                    ComponentAttributeSetting setting = component.getSingleAttributeSetting(record.getAttributeId(),
                            key);

                    String oldValue = setting == null ? Boolean.FALSE.toString() : setting.getValue();
                    if (setting == null) {
                        setting = new ComponentAttributeSetting(record.getAttributeId(), component.getId(), key,
                                Boolean.FALSE.toString());
                        component.addAttributeSetting(setting);
                    }
                    setting.setValue(checkBox.getValue().toString());
                    if (!oldValue.equals(setting.getValue())) {
                        context.getConfigurationService().save(setting);
                        Set<RecordFormat> attributes = new HashSet<>();
                        attributes.add(record);

                        if (oldValue.equals(Boolean.FALSE.toString())) {
                            moveItemsTo(attributes,
                                    getLastSortItemIndex(record.getEntityId(), record.getAttributeId(), true) + 1);
                        } else {
                            moveItemsTo(attributes,
                                    getLastSortItemIndex(record.getEntityId(), record.getAttributeId(), false));
                        }
                    }

                    calculatePositions();
                    saveOrdinalSettings();
                    saveSortSettings();
                }
            });
            return checkBox;
        }

        protected void focusOn(RecordFormat record, Object propertyId) {
            record.setFocusFieldId(propertyId);
            for (Object itemId : getSelectedItems()) {
                table.unselect(itemId);
            }
            table.select(record);
        }
    }

    class TableCellStyleGenerator implements CellStyleGenerator {
        public String getStyle(Table source, Object itemId, Object propertyId) {
            if (propertyId != null && selectedItemIds != null && selectedItemIds.contains(itemId)) {
                return "highlight";
            }
            return null;
        }
    }

    public class RecordFormat {
        ModelEntity modelEntity;

        ModelAttribute modelAttribute;

        Map<Object, Field<?>> fields = new HashMap<Object, Field<?>>();

        Object focusFieldId;

        boolean sortSetting = false;

        int ordinalSetting;

        public RecordFormat(ModelEntity modelEntity, ModelAttribute modelAttribute) {
            this.modelEntity = modelEntity;
            this.modelAttribute = modelAttribute;

            if (modelAttribute != null) {
                ComponentAttributeSetting setting = component.getSingleAttributeSetting(modelAttribute.getId(),
                        Sorter.SORTER_ATTRIBUTE_ORDINAL);
                if (setting != null) {
                    this.ordinalSetting = Integer.parseInt(setting.getValue());
                }

                setting = component.getSingleAttributeSetting(modelAttribute.getId(),
                        Sorter.ATTRIBUTE_SORTER_ENABLED);
                if (setting != null) {
                    this.sortSetting = Boolean.parseBoolean(setting.getValue());
                }
            } else {
                ComponentEntitySetting setting = component.getSingleEntitySetting(modelEntity.getId(),
                        Sorter.SORTER_ATTRIBUTE_ORDINAL);
                if (setting != null) {
                    this.ordinalSetting = Integer.parseInt(setting.getValue());
                }

                setting = component.getSingleEntitySetting(modelEntity.getId(), Sorter.ATTRIBUTE_SORTER_ENABLED);
                if (setting != null) {
                    this.sortSetting = Boolean.parseBoolean(setting.getValue());
                }
            }
        }

        public int hashCode() {
            return modelEntity.hashCode() + modelAttribute.hashCode();
        }

        public boolean equals(Object obj) {
            if (obj instanceof RecordFormat) {
                return hashCode() == ((RecordFormat) obj).hashCode();
            }
            return super.equals(obj);
        }

        public String getEntityName() {
            return modelEntity.getName();
        }

        public String getEntityId() {
            return modelEntity.getId();
        }

        public String getAttributeName() {
            return modelAttribute.getName();
        }

        public String getAttributeId() {
            return modelAttribute.getId();
        }

        public boolean getSortSetting() {
            return sortSetting;
        }

        public void setSortSetting(boolean sortSetting) {
            this.sortSetting = sortSetting;
        }

        public void addField(Object id, Field<?> field) {
            fields.put(id, field);
        }

        public void setFocusFieldId(Object id) {
            this.focusFieldId = id;
        }

        public Field<?> getFocusField() {
            Field<?> field = fields.get(focusFieldId);
            if (field == null) {
                field = fields.get("width");
            }
            return field;
        }

        public int getOrdinalSetting() {
            return ordinalSetting;
        }

        public void setOrdinalSetting(int ordinalSetting) {
            this.ordinalSetting = ordinalSetting;
        }
    }
}