/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Categorizer.java * Creation date: Oct 28, 2002. * By: Edward Lam */ package org.openquark.gems.client.browser; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import org.openquark.cal.services.GemEntity; /** * A GemCategorizer breaks up a collection of entities into named (and optionally sorted) categories. * * @author Edward Lam */ public abstract class GemCategorizer<T> { /** * List of keys representing categories. The keys for the categories to include, * in the order in which they should be returned. */ private final List<T> categoriesToInclude; /** * Whether new categories should be formed if not in the list of provided categories. * If false, any entity whose category does not fall into the list of categories will not be included. */ private final boolean formNewCategories; /** * Constructor for a Categorizer. * This categorizer will form categories based on the categorized entities, and sort the categories. */ public GemCategorizer() { this(Collections.<T>emptyList(), true); } /** * Constructor for a GemCategorizer * @param categoriesToInclude List of keys representing categories. * The keys for the categories to include, in the order in which they should be returned. * Passing null is equivalent to passing an empty list. * @param formNewCategories Whether new categories should be formed if not in the list of provided categories. * If false, any entity whose category does not fall into the list of categories will not be included. * If true, in the absence of a specified ordering, any new categories will be included after the * provided categories. */ public GemCategorizer(List<T> categoriesToInclude, boolean formNewCategories) { if (categoriesToInclude == null) { categoriesToInclude = Collections.emptyList(); } this.categoriesToInclude = categoriesToInclude; this.formNewCategories = formNewCategories; } /** * Compares its two arguments for order. Returns a negative integer, zero, or a positive integer * as the first argument is less than, equal to, or greater than the second.<p> * The default implementation considers all keys to be equal, meaning that categories will be returned * in the order in which they are encountered in the entity list. * Subclasses in which categories should exhibit a given ordering should override this method. * @param key1 the first object to be compared. * @param key2 the second object to be compared. * @return int a negative integer, zero, or a positive integer as the first argument * is less than, equal to, or greater than the second. */ public abstract int compareKey(GemCategory.CategoryKey<T> key1, GemCategory.CategoryKey<T> key2); /** * Return a list of keys representing all of the categories that an entity belongs to. * Most implementations should return a single-element list. * * @param gemEntity The entity to generate a list of categories for * @return List of category keys */ public abstract List<GemCategory.CategoryKey<T>> getCategoryKeyList(GemEntity gemEntity); /** * Form the given gemEntities into categories. * @param gemEntities the entities to categorize. * @return List the categories */ public List<GemCategory> formCategories(Collection<GemEntity> gemEntities) { // Create the categories provided (if any) Map<GemCategory.CategoryKey<T>, List<GemEntity>> keyToCategoryItemsListMap = new HashMap<GemCategory.CategoryKey<T>, List<GemEntity>>(); for (final T key : categoriesToInclude) { GemCategory.CategoryKey<T> categoryKey = new GemCategory.CategoryKey<T>(key); keyToCategoryItemsListMap.put(categoryKey, new ArrayList<GemEntity>()); } // Now place the items into category lists. for (final GemEntity gemEntity : gemEntities) { List<GemCategory.CategoryKey<T>> gemCategories = getCategoryKeyList(gemEntity); // Add the gem to each of the categories that apply to it for (final GemCategory.CategoryKey<T> categoryKey : gemCategories) { List<GemEntity> category = keyToCategoryItemsListMap.get(categoryKey); // Create a new category if appropriate. if (category == null) { // skip if we don't form new categories. if (!formNewCategories) { continue; } category = new ArrayList<GemEntity>(); keyToCategoryItemsListMap.put(categoryKey, category); } category.add(gemEntity); } } // Grab the category keys and sort them. List<GemCategory.CategoryKey<T>> categoryKeys = new ArrayList<GemCategory.CategoryKey<T>>(keyToCategoryItemsListMap.keySet()); Comparator<GemCategory.CategoryKey<T>> keyComparator = new Comparator<GemCategory.CategoryKey<T>>() { public int compare(GemCategory.CategoryKey<T> o1, GemCategory.CategoryKey<T> o2) { return compareKey(o1, o2); } }; Collections.sort(categoryKeys, keyComparator); // Form the categories List<GemCategory> categoryList = new ArrayList<GemCategory>(categoryKeys.size()); for (final GemCategory.CategoryKey<T> categoryKey : categoryKeys) { List<GemEntity> category = keyToCategoryItemsListMap.get(categoryKey); categoryList.add(new GemCategory(categoryKey, category)); } return categoryList; } }