/******************************************************************************* * Copyright 2006 - 2012 Vienna University of Technology, * Department of Software Technology and Interactive Systems, IFS * * 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 eu.scape_project.planning.bean; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EventListener; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import javax.inject.Inject; import eu.scape_project.planning.manager.CriteriaManager; import eu.scape_project.planning.model.measurement.Attribute; import eu.scape_project.planning.model.measurement.CriterionCategory; import eu.scape_project.planning.model.measurement.Measure; public class CriterionSelector implements Serializable { private static final long serialVersionUID = -2370084698959293108L; /** * Listener for change events of the selector. */ public interface ChangeListener extends EventListener { /** * Called when a category, attribute or measure is selected. */ void selected(); } @Inject private CriteriaManager criteriaManager; private List<CriterionCategory> categories; private List<Attribute> allAttributes; private List<Attribute> filteredAttributes; private List<Measure> allMeasures; private List<Measure> filteredMeasures; private CriterionCategory selectedCategory; private Attribute selectedAttribute; private Measure selectedMeasure; private String searchTerm; private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>(1); /** * Compares two category instances regarding their name. */ class CategoryNameComparator implements Comparator<CriterionCategory> { @Override public int compare(CriterionCategory o1, CriterionCategory o2) { if (null == o1) { return -1; } else if (null == o2) { return 1; } return o1.getName().compareTo(o2.getName()); } } /** * Compares two attribute instances regarding their name. */ class AttributeNameComparator implements Comparator<Attribute> { @Override public int compare(Attribute o1, Attribute o2) { if (null == o1) { return -1; } else if (null == o2) { return 1; } return o1.getName().compareTo(o2.getName()); } } /** * Compares two measure instances regarding their name. */ class MeasureNameComparator implements Comparator<Measure> { @Override public int compare(Measure o1, Measure o2) { if (null == o1) { return -1; } else if (null == o2) { return 1; } return o1.getName().compareTo(o2.getName()); } } /** * Creates a new criterion selector object. */ public CriterionSelector() { clearSelection(); } /** * Initializes the Measure selection. Retrieves all available measures from * the {@link #criteriaManager CriteriaManager} */ public void init() { allMeasures = new ArrayList<Measure>(criteriaManager.getAllMeasures()); allAttributes = new ArrayList<Attribute>(); categories = new ArrayList<CriterionCategory>(); // show only attributes and categories for which measures exist for (Measure m : allMeasures) { if (!allAttributes.contains(m.getAttribute())) { allAttributes.add(m.getAttribute()); } } for (Attribute a : allAttributes) { if (!categories.contains(a.getCategory())) { categories.add(a.getCategory()); } } Collections.sort(allMeasures, new MeasureNameComparator()); Collections.sort(allAttributes, new AttributeNameComparator()); Collections.sort(categories, new CategoryNameComparator()); changeListeners.clear(); clearSelection(); } /** * Removes all measures from the list of available measures where the uris * are not in the given set of uris. * * @param measureUris * The uris of the measures which shall be available for * selection. */ public void filterCriteria(Set<String> measureUris) { HashMap<String, CriterionCategory> filteredCategories = new HashMap<String, CriterionCategory>(); HashMap<String, Attribute> filteredAttributes = new HashMap<String, Attribute>(); HashMap<String, Measure> filteredMeasures = new HashMap<String, Measure>(); for (Measure m : allMeasures) { if (measureUris.contains(m.getUri())) { filteredMeasures.put(m.getUri(), m); filteredAttributes.put(m.getAttribute().getUri(), m.getAttribute()); filteredCategories.put(m.getAttribute().getCategory().getUri(), m.getAttribute().getCategory()); } } categories.clear(); categories.addAll(filteredCategories.values()); allAttributes.clear(); allAttributes.addAll(filteredAttributes.values()); allMeasures.clear(); allMeasures.addAll(filteredMeasures.values()); } /** * Clears the currently selected attribute, measure and searchTerm. */ private void clearSelection() { filteredAttributes = new ArrayList<Attribute>(); filteredMeasures = new ArrayList<Measure>(); selectedCategory = null; selectedAttribute = null; selectedMeasure = null; searchTerm = ""; } /** * Returns the name of the selected category. * * @return the category name or null if no category selected */ public String getSelectedCategoryName() { if (selectedCategory == null) { return null; } else { return selectedCategory.getName(); } } /** * Sets the selected category by name. * * @param name * the category name */ public void setSelectedCategoryName(String name) { this.selectedCategory = findCategoryByName(name); } /** * Sets the selected attribute by name. * * @param name * the attribute name */ public void setSelectedAttributeName(String name) { selectedAttribute = findAttributeByName(name); } /** * Finds a category by name. * * @param name * the category name * @return the category or null if no matching category found */ private CriterionCategory findCategoryByName(String name) { if (name == null) { return null; } for (CriterionCategory c : categories) { if (name.equals(c.getName())) { return c; } } return null; } /** * Finds an attribute by name. * * @param name * the attribute name * @return the attribute or null if no matching attribute found */ private Attribute findAttributeByName(String name) { if (name == null) { return null; } for (Attribute a : allAttributes) { if (name.equals(a.getName())) { return a; } } return null; } /** * Finds the measure by name. * * @param name * the measure name * @return the measure or null if no matching measure found */ private Measure findMeasureByName(String name) { if (name == null) { return null; } for (Measure a : allMeasures) { if (name.equals(a.getName())) { return a; } } return null; } /** * Returns the name of the selected attribute. * * @return the attribute name or null if no attribute selected */ public String getSelectedAttributeName() { if (selectedAttribute == null) { return null; } else { return selectedAttribute.getName(); } } /** * Sets the selected measure by name. * * @param name * the measure name */ public void setSelectedMeasureName(String name) { selectedMeasure = findMeasureByName(name); } /** * Returns the name of the selected measure. * * @return the measure name of null if no measure selected */ public String getSelectedMeasureName() { if (selectedMeasure == null) { return null; } else { return selectedMeasure.getName(); } } /** * Searches for measures which comply to the currently set * {@link #searchTerm}. To be called when the search term has changed. */ public void updateSearch() { String[] terms = searchTerm.split("\\s"); String pattern = "^"; for (int i = 0; i < terms.length; i++) { // we use pattern += "(?=.*" + terms[i] + ")"; } pattern += ".*"; Pattern searchPattern; try { searchPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); } catch (IllegalArgumentException e) { searchPattern = Pattern.compile(".*", Pattern.CASE_INSENSITIVE); } Set<Attribute> termFilteredAttributes = new HashSet<Attribute>(); filteredMeasures.clear(); for (Measure m : allMeasures) { // search in all descriptions at once, this is more what the user // expects String base = m.getName() + " " + m.getDescription() + " " + m.getAttribute().getName() + " " + m.getAttribute().getDescription() + " " + m.getAttribute().getCategory().getName(); if (searchPattern.matcher(base).matches()) { filteredMeasures.add(m); termFilteredAttributes.add(m.getAttribute()); } } filteredAttributes.clear(); filteredAttributes.addAll(termFilteredAttributes); Collections.sort(filteredMeasures, new MeasureNameComparator()); Collections.sort(filteredAttributes, new AttributeNameComparator()); } /** * Notifies this object that a category was selected. */ public void categorySelected() { filteredAttributes.clear(); if (selectedCategory != null) { for (Attribute attr : allAttributes) { if (attr.getCategory().getUri().equals(selectedCategory.getUri())) { filteredAttributes.add(attr); } } } if (!filteredAttributes.contains(selectedAttribute)) { selectedAttribute = null; } // if there is only one attribute, preselect it if (filteredAttributes.size() == 1) { selectedAttribute = filteredAttributes.iterator().next(); } // propagate the new selection attributeSelected(); } /** * Notifies this object that a attribute was selected. */ public void attributeSelected() { filteredMeasures.clear(); if (selectedAttribute != null) { for (Measure m : allMeasures) { if (m.getAttribute().getUri().equals(selectedAttribute.getUri())) { filteredMeasures.add(m); } } // and also adjust the category, in case the textual filter was used if ((selectedCategory == null) || (!selectedCategory.getUri().equals(selectedAttribute.getCategory().getUri()))) { selectedCategory = selectedAttribute.getCategory(); } } if (!filteredMeasures.contains(selectedMeasure)) { selectedMeasure = null; } // if there is only one measure, preselect it if (filteredMeasures.size() == 1) { selectedMeasure = filteredMeasures.iterator().next(); } setSearchTerm(""); // propagate the new selection measureSelected(); } /** * Notifies this object that a measure was selected. */ public void measureSelected() { if (selectedMeasure != null) { if ((selectedAttribute == null) || (!selectedAttribute.getUri().equals(selectedMeasure.getAttribute().getUri()))) { selectedAttribute = findAttributeByName(selectedMeasure.getAttribute().getName()); selectedCategory = findCategoryByName(selectedAttribute.getCategory().getName()); } } callChangeListeners(); } /** * Calls registered listeners. */ private void callChangeListeners() { for (ChangeListener c : changeListeners) { c.selected(); } } /** * Selects the provided measures. * * @param measure * the measure to select */ public void selectMeasure(Measure measure) { if (measure != null) { selectedMeasure = measure; measureSelected(); categorySelected(); selectedMeasure = measure; } else { clearSelection(); } } /** * Adds a change listener to this object. * * @param changeListener * the change listener to add */ public void addChangeListener(ChangeListener changeListener) { changeListeners.add(changeListener); } /** * Removes a change listener from this object. * * @param changeListener * the change listener to remove */ public void removeChangeListener(ChangeListener changeListener) { changeListeners.remove(changeListener); } public Measure getSelectedMeasure() { return selectedMeasure; } public Collection<CriterionCategory> getCategories() { return categories; } public Collection<Measure> getFilteredMeasures() { return filteredMeasures; } public Collection<Attribute> getFilteredAttributes() { return filteredAttributes; } public Attribute getSelectedAttribute() { return selectedAttribute; } public CriterionCategory getSelectedCategory() { return selectedCategory; } public String getSearchTerm() { return searchTerm; } public void setSearchTerm(String value) { this.searchTerm = value; } }