package org.esa.snap.rcp.imgfilter; import org.esa.snap.rcp.imgfilter.model.Filter; import org.esa.snap.rcp.imgfilter.model.FilterSet; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * The internal model for a {@code JTree} displaying a {@link FilterSet}. * * @author Norman */ class FilterTreeModel implements TreeModel, FilterSet.Listener { private final Root root; private final ArrayList<TreeModelListener> listeners; private final FilterSet filterSet; public FilterTreeModel(FilterSet filterSet) { this.filterSet = filterSet; this.filterSet.addListener(this); root = new Root(); listeners = new ArrayList<>(); createTreeNodes(); } public void addFilter(Filter filter, TreePath selectionPath) { if (selectionPath != null) { Object[] path = selectionPath.getPath(); if (path.length >= 2) { Group group = (Group) path[1]; filter.getTags().add(group.name); } } filterSet.addFilter(filter); } public void removeFilter(Filter filter) { filterSet.removeFilter(filter); } public TreePath getFilterPath(Filter filter) { for (Group group : root.groups) { for (Filter filter1 : group.filters) { if (filter1 == filter) { return new TreePath(new Object[] {root, group, filter}); } } } return null; } @Override public void filterAdded(FilterSet filterSet, Filter filter) { insertTreeNodes(filter); } @Override public void filterRemoved(FilterSet filterSet, Filter filter) { removeTreeNodes(filter); } @Override public void filterChanged(FilterSet filterSet, Filter filter, String propertyName) { if ("tags".equals(propertyName)) { createTreeNodes(); fireTreeStructureChanged(); } else { fireTreeNodesChanged(filter); } } @Override public Object getRoot() { return root; } @Override public Object getChild(Object parent, int index) { if (parent == root) { return root.groups.get(index); } else if (parent instanceof Group) { return ((Group) parent).filters.get(index); } return null; } @Override public int getChildCount(Object parent) { if (parent == root) { return root.groups.size(); } else if (parent instanceof Group) { return ((Group) parent).filters.size(); } return 0; } @Override public int getIndexOfChild(Object parent, Object child) { if (parent == root) { return root.groups.indexOf(child); } else if (parent instanceof Group) { return ((Group) parent).filters.indexOf(child); } return -1; } @Override public boolean isLeaf(Object node) { return node instanceof Filter; } @Override public void valueForPathChanged(TreePath treePath, Object newValue) { /* System.out.print("valueForPathChanged: "); for (Object node : treePath.getPath()) { System.out.print("/" + node); } System.out.print(" = " + newValue); */ //notifyTreeNodeChanged(treePath); } @Override public void addTreeModelListener(TreeModelListener l) { listeners.add(l); } @Override public void removeTreeModelListener(TreeModelListener l) { listeners.remove(l); } private synchronized void insertTreeNodes(Filter filter) { HashSet<String> remainingTags = new HashSet<>(filter.getTags()); if (filter.getTags().isEmpty() || filter.getTags().contains(root.any.name )) { Group group = root.any; if (!root.groups.contains(group)) { _addGroup(group); } _addFilter(group, filter); remainingTags.remove(group.name); if (remainingTags.isEmpty()) { return; } } for (Group group : root.groups) { if (filter.getTags().contains(group.name) || filter.getTags().isEmpty() && group == root.any) { _addFilter(group, filter); remainingTags.remove(group.name); } } for (String remainingTag : remainingTags) { Group group = new Group(remainingTag); _addGroup(group); _addFilter(group, filter); } } private void _addGroup(Group group) { root.groups.add(group); fireTreeNodeInserted(root.groups.size() - 1, group); } private void _addFilter(Group group, Filter filter) { group.filters.add(filter); fireTreeNodeInserted(group, group.filters.size() - 1, filter); } private synchronized void removeTreeNodes(Filter filter) { int groupIndex = 0; while (groupIndex < root.groups.size()) { Group group = root.groups.get(groupIndex); int filterIndex = group.filters.indexOf(filter); if (filterIndex >= 0) { group.filters.remove(filterIndex); if (group.filters.isEmpty() && group != root.any) { root.groups.remove(groupIndex); fireTreeNodeRemoved(groupIndex, group); } else { fireTreeNodeRemoved(group, filterIndex, filter); groupIndex++; } } else { groupIndex++; } } } private void fireTreeNodeInserted(int groupIndex, Group group) { fireTreeNodesInserted(new TreeModelEvent(this, getPath(root), new int[]{groupIndex}, new Object[]{group})); } private void fireTreeNodeInserted(Group group, int filterIndex, Filter filter) { fireTreeNodesInserted(new TreeModelEvent(this, getPath(root, group), new int[]{filterIndex}, new Object[]{filter})); } private void fireTreeNodesInserted(TreeModelEvent treeModelEvent) { for (TreeModelListener listener : listeners) { listener.treeNodesInserted(treeModelEvent); } } private void fireTreeNodeRemoved(int groupIndex, Group group) { fireTreeNodesRemoved(new TreeModelEvent(this, getPath(root), new int[]{groupIndex}, new Object[]{group})); } private void fireTreeNodeRemoved(Group group, int filterIndex, Filter filter) { fireTreeNodesRemoved(new TreeModelEvent(this, getPath(root, group), new int[]{filterIndex}, new Object[]{filter})); } private void fireTreeNodesRemoved(TreeModelEvent treeModelEvent) { for (TreeModelListener listener : listeners) { listener.treeNodesRemoved(treeModelEvent); } } private void fireTreeNodesChanged(Filter filter) { for (Group group : root.groups) { for (Filter filter1 : group.filters) { if (filter1 == filter) { fireTreeNodeChanged(group, filter); } } } } private void fireTreeNodeChanged(Group group, Filter filter) { fireTreeNodesChanged(new TreeModelEvent(this, getPath(root, group, filter))); } private void fireTreeNodesChanged(TreeModelEvent treeModelEvent) { for (TreeModelListener listener : listeners) { listener.treeNodesChanged(treeModelEvent); } } public void fireTreeStructureChanged() { TreeModelEvent treeModelEvent = new TreeModelEvent(this, getPath(root)); for (TreeModelListener listener : listeners) { listener.treeStructureChanged(treeModelEvent); } } static Object[] getPath(Object ... path) { return path; } private void createTreeNodes() { root.any.filters.clear(); root.groups.clear(); List<Filter> filters = filterSet.getFilters(); for (Filter filter : filters) { insertTreeNodes(filter); } } public static class Root { final Group any = new Group("Any"); final List<Group> groups; private Root() { this.groups = new ArrayList<>(); } @Override public String toString() { return "Root"; } } public static class Group implements Comparable<Group> { final String name; final String nameLC; final List<Filter> filters; private Group(String name) { this.name = name; this.nameLC = name.toLowerCase(); filters = new ArrayList<>(); } @Override public String toString() { return name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Group group = (Group) o; return name.equalsIgnoreCase(group.name); } @Override public int hashCode() { return nameLC.hashCode(); } @Override public int compareTo(Group group) { return name.compareToIgnoreCase(group.name); } } }