Package org.thechiselgroup.choosel.core.client.views.model

Source Code of org.thechiselgroup.choosel.core.client.views.model.DefaultViewItem

/*******************************************************************************
* Copyright 2009, 2010 Lars Grammel
*
* 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.thechiselgroup.choosel.core.client.views.model;

import java.util.Map;

import org.thechiselgroup.choosel.core.client.resources.DefaultResourceSet;
import org.thechiselgroup.choosel.core.client.resources.Resource;
import org.thechiselgroup.choosel.core.client.resources.ResourceSet;
import org.thechiselgroup.choosel.core.client.resources.ResourceSetChangedEvent;
import org.thechiselgroup.choosel.core.client.resources.ResourceSetChangedEventHandler;
import org.thechiselgroup.choosel.core.client.util.Disposable;
import org.thechiselgroup.choosel.core.client.util.collections.CollectionFactory;
import org.thechiselgroup.choosel.core.client.util.collections.LightweightCollection;
import org.thechiselgroup.choosel.core.client.util.event.EventHandlerPriority;
import org.thechiselgroup.choosel.core.client.util.event.PrioritizedEventHandler;

/**
* Default implementation of {@link ViewItem}.
* <p>
* <b>PERFORMANCE NOTE</b>: Provides caching for calculated slot values and for
* highlighting and selection status.
* </p>
*
* @author Lars Grammel
*/
// TODO separate out resource item controller part
public class DefaultViewItem implements Disposable, ViewItem {

    private final class CacheUpdateOnResourceSetChange implements
            ResourceSetChangedEventHandler, PrioritizedEventHandler {

        @Override
        public EventHandlerPriority getPriority() {
            return EventHandlerPriority.FIRST;
        }

        @Override
        public void onResourceSetChanged(ResourceSetChangedEvent event) {
            cache.clear();
        }
    }

    private final class CacheUpdateOnSlotChange implements
            SlotMappingChangedHandler, PrioritizedEventHandler {

        @Override
        public EventHandlerPriority getPriority() {
            return EventHandlerPriority.FIRST;
        }

        @Override
        public void onResourceCategoriesChanged(SlotMappingChangedEvent e) {
            String slotId = e.getSlot().getId();

            cache.remove(slotId);
        }
    }

    private String viewItemID;

    // TODO update & paint on changes in resources!!!
    private final ResourceSet resources;

    private final SlotMappingConfiguration slotMappingConfiguration;

    /**
     * The representation of this resource item in the specific display. This is
     * set by the display to enable fast reference to this display element, and
     * should be casted into the specific type.
     */
    // TODO dispose
    private Object displayObject;

    private ResourceSet highlightedResources;

    private ResourceSet selectedResources;

    private Status cachedHighlightStatus = null;

    private Status cachedSelectedStatus = null;

    /**
     * PERFORMANCE: Cache for the resolved slot values of ALL subset. Maps the
     * slot id to the value.
     */
    private Map<String, Object> cache = CollectionFactory.createStringMap();

    private final ViewItemInteractionHandler interactionHandler;

    public DefaultViewItem(String viewItemID, ResourceSet resources,
            SlotMappingConfiguration slotMappingConfiguration,
            ViewItemInteractionHandler interactionHandler) {

        assert viewItemID != null;
        assert resources != null;
        assert slotMappingConfiguration != null;
        assert interactionHandler != null;

        this.viewItemID = viewItemID;
        this.resources = resources;
        this.slotMappingConfiguration = slotMappingConfiguration;
        this.interactionHandler = interactionHandler;

        highlightedResources = new DefaultResourceSet();
        selectedResources = new DefaultResourceSet();

        initCacheCleaning(resources, slotMappingConfiguration);

        resources.addEventHandler(new ResourceSetChangedEventHandler() {
            @Override
            public void onResourceSetChanged(ResourceSetChangedEvent event) {
                LightweightCollection<Resource> removedResources = event
                        .getRemovedResources();

                highlightedResources.removeAll(removedResources);
                selectedResources.removeAll(removedResources);
            }
        });
    }

    @Override
    public void dispose() {
        // XXX deregister event listeners
        // XXX dispose intersection sets

    }

    @Override
    public Object getDisplayObject() {
        return displayObject;
    }

    private Status getHighlightStatus() {
        if (cachedHighlightStatus == null) {
            cachedHighlightStatus = getSubsetStatus(highlightedResources);
        }

        return cachedHighlightStatus;
    }

    @Override
    public ResourceSet getResources() {
        return resources;
    }

    @Override
    public ResourceSet getResources(Subset subset) {
        assert subset != null;
        switch (subset) {
        case ALL:
            return getResources();
        case HIGHLIGHTED:
            return highlightedResources;
        case SELECTED:
            return selectedResources;
        default:
            throw new RuntimeException("should not be reached");
        }
    }

    private Status getSelectionStatus() {
        if (cachedSelectedStatus == null) {
            cachedSelectedStatus = getSubsetStatus(selectedResources);
        }

        return cachedSelectedStatus;
    }

    // TODO move, refactor
    @Override
    public Slot[] getSlots() {
        return slotMappingConfiguration.getSlots().toArray(
                new Slot[slotMappingConfiguration.getSlots().size()]);
    }

    @Override
    public Status getStatus(Subset subset) {
        assert subset != null;
        switch (subset) {
        case ALL:
            // always containing all contained resources
            return Status.FULL;
        case HIGHLIGHTED:
            return getHighlightStatus();
        case SELECTED:
            return getSelectionStatus();
        default:
            throw new RuntimeException("should not be reached");
        }
    }

    private Status getSubsetStatus(ResourceSet subset) {
        if (subset.isEmpty()) {
            return Status.NONE;
        }

        if (subset.containsEqualResources(resources)) {
            return Status.FULL;
        }

        return Status.PARTIAL;
    }

    @Override
    public <T> T getValue(Slot slot) {
        assert slot != null : "slot must not be null";

        String slotId = slot.getId();
        if (cache.containsKey(slotId)) {
            return (T) cache.get(slotId);
        }

        Object value = slotMappingConfiguration.resolve(slot, this);

        cache.put(slotId, value);

        return (T) value;
    }

    @Override
    public double getValueAsDouble(Slot slot) {
        return this.<Number> getValue(slot).doubleValue();
    }

    @Override
    public String getViewItemID() {
        return viewItemID;
    }

    public void initCacheCleaning(ResourceSet resources,
            SlotMappingConfiguration slotMappingConfiguration) {
        resources.addEventHandler(new CacheUpdateOnResourceSetChange());
        slotMappingConfiguration.addHandler(new CacheUpdateOnSlotChange());
    }

    @Override
    public boolean isStatus(Subset subset, Status... status) {
        Status realStatus = getStatus(subset);
        for (Status expectedStatus : status) {
            if (realStatus.equals(expectedStatus)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public void reportInteraction(ViewItemInteraction interaction) {
        assert interaction != null;
        interactionHandler.onInteraction(this, interaction);
    }

    @Override
    public void setDisplayObject(Object displayObject) {
        this.displayObject = displayObject;
    }

    @Override
    public String toString() {
        return "ViewItem[" + resources.toString() + "]";
    }

    public void updateHighlightedResources(
            LightweightCollection<Resource> addedHighlightedResources,
            LightweightCollection<Resource> removedHighlightedResources) {

        assert addedHighlightedResources != null;
        assert removedHighlightedResources != null;

        cachedHighlightStatus = null;
        cache.clear();

        highlightedResources.addAll(resources
                .getIntersection(addedHighlightedResources));
        highlightedResources.removeAll(resources
                .getIntersection(removedHighlightedResources));
    }

    public void updateSelectedResources(
            LightweightCollection<Resource> addedSelectedResources,
            LightweightCollection<Resource> removedSelectedResources) {

        assert addedSelectedResources != null;
        assert removedSelectedResources != null;

        cachedSelectedStatus = null;
        cache.clear();

        selectedResources.addAll(resources
                .getIntersection(addedSelectedResources));
        selectedResources.removeAll(resources
                .getIntersection(removedSelectedResources));
    }

}
TOP

Related Classes of org.thechiselgroup.choosel.core.client.views.model.DefaultViewItem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.