package fr.inria.soctrace.framesoc.ui.treefilter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Shell; import org.eclipse.wb.swt.ResourceManager; import fr.inria.soctrace.framesoc.ui.Activator; import fr.inria.soctrace.framesoc.ui.model.IModelElementNode; import fr.inria.soctrace.framesoc.ui.model.ITreeNode; import fr.inria.soctrace.framesoc.ui.providers.TreeContentProvider; /** * Manager class for filter data. * * This class stores the data needed to display and process filters on a dimension like event * producers or event types. It provides the methods for creating the corresponding actions and * dialogs. * * @author "Generoso Pagano <generoso.pagano@inria.fr>" */ public abstract class FilterDataManager { /** * Filter status */ private static enum FilterStatus { UNSET, SET, APPLIED; } private FilterDimensionData dimensionData; private IAction filterAction; private TreeFilterDialog filterDialog; private ITreeNode[] roots; private List<Object> checked; private List<Object> allElements; /** * Constructor * * @param dimensionData * dimension managed by the filter */ public FilterDataManager(FilterDimensionData dimensionData) { this.dimensionData = dimensionData; } /** * @return the configuration dimension */ public FilterDimension getDimension() { return dimensionData.getFilterDimension(); } /** * Initialize the filter action * * @return the action */ public IAction initFilterAction() { filterAction = new Action("", IAction.AS_CHECK_BOX) { @Override public void run() { showFilterAction(); } }; filterAction.setImageDescriptor(ResourceManager.getPluginImageDescriptor( Activator.PLUGIN_ID, "icons/" + dimensionData.getIconName())); filterAction.setToolTipText(dimensionData.getActionToolTipMessage()); return filterAction; } /** * Initialize the filter dialog * * @param shell * the shell */ public void initFilterDialog(Shell shell) { filterDialog = new TreeFilterDialog(shell); filterDialog.setColumnNames(new String[] { dimensionData.getName() }); filterDialog.setContentProvider(new TreeContentProvider()); filterDialog.setLabelProvider(dimensionData.getLabelProvider()); } /** * Set the input for the filter tree viewer. * * @param rootNodes * the array of tree roots */ public void setFilterRoots(ITreeNode[] rootNodes) { roots = rootNodes; checked = TreeFilterDialog.listAllInputs(new ArrayList<ITreeNode>(Arrays.asList(roots))); allElements = new ArrayList<>(checked); filterAction.setChecked(false); } /** * Get the id of the configuration dimension entity corresponding to checked items (e.g., * checked event producers ids). * * @return */ public List<Integer> getCheckedId() { List<Integer> toLoad = new ArrayList<Integer>(checked.size()); for (Object o : checked) { if (!(o instanceof IModelElementNode)) { continue; } toLoad.add(((IModelElementNode) o).getId()); } return toLoad; } /** * Return a copy of the list of checked items. * * @return a copy of the list containing the checked items. */ public List<Object> getChecked() { return new ArrayList<Object>(checked); } /** * Set the element of the filters that are not filtered out * * @param elements * the list of elements (should be ITreeNode) that are not * filtered */ public void setChecked(List<Object> elements) { checked.clear(); checked.addAll(elements); // Set the state of the filter button filterAction.setChecked(elements.size() != allElements.size()); } /** * * @return A list of all the elements in the tree */ public List<Object> getAllElements() { return allElements; } /** * Check if the passed list is equals to the checked items. * * @param c * list of items * @return true if the passed list contains the same items as the list of checked items. */ public boolean areCheckedEqual(List<Object> c) { return areListsEqual(c, checked); } /** * Handler called after the filtering configuration has been changed. */ public abstract void reloadAfterChange(); /* * Utilities */ private void showFilterAction() { if (roots.length > 0) { filterDialog.setInput(roots); filterDialog.setTitle(dimensionData.getName() + " Filter"); filterDialog.setMessage(dimensionData.getDialogMessage()); filterDialog.setExpandedElements(allElements.toArray()); filterDialog.setInitialElementSelections(checked); filterDialog.create(); // reset checked status, managed manually filterAction.setChecked(!filterAction.isChecked()); // open the dialog if (filterDialog.open() != Window.OK) { return; } // Process selected elements if (filterDialog.getResult() != null) { List<Object> currentChecked = new ArrayList<Object>(Arrays.asList(filterDialog.getResult())); if (areListsEqual(allElements, currentChecked)) { // all checked if (areListsEqual(allElements, checked)) { updateFilter(FilterStatus.UNSET); } else { // the loaded data is with unchecked elements updateFilter(FilterStatus.SET); checked = currentChecked; reloadAfterChange(); updateFilter(FilterStatus.UNSET); } } else if (areListsEqual(checked, currentChecked)) { updateFilter(FilterStatus.APPLIED); } else { updateFilter(FilterStatus.SET); checked = currentChecked; reloadAfterChange(); updateFilter(FilterStatus.APPLIED); } } } } private void updateFilter(FilterStatus status) { StringBuilder icon = new StringBuilder("icons/"); StringBuilder tooltip = new StringBuilder("Show " + dimensionData.getName() + " Filter"); switch (status) { case APPLIED: filterAction.setChecked(true); icon.append(dimensionData.getAppliedIconName()); tooltip.append(" (filter applied)"); break; case SET: filterAction.setChecked(false); icon.append(dimensionData.getSetIconName()); tooltip.append(" (filter set but not applied)"); break; case UNSET: filterAction.setChecked(false); icon.append(dimensionData.getIconName()); break; } filterAction.setImageDescriptor(ResourceManager.getPluginImageDescriptor( Activator.PLUGIN_ID, icon.toString())); filterAction.setToolTipText(tooltip.toString()); } private boolean areListsEqual(List<Object> l1, List<Object> l2) { if (l1 == null) { return l2 == null; } if (l2 == null) { return l1 == null; } Set<Object> s1 = new HashSet<>(l1); Set<Object> s2 = new HashSet<>(l2); return s1.equals(s2); } }