// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package com.amalto.workbench.editors.xsdeditor;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.xsd.XSDAnnotation;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDIdentityConstraintDefinition;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDModelGroupDefinition;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDSimpleTypeDefinition;
import org.eclipse.xsd.XSDTypeDefinition;
import com.amalto.workbench.editors.DataModelMainPage;
import com.amalto.workbench.providers.datamodel.SchemaTreeContentProvider;
/**
* created by liusonbo on 2013-6-8
*/
public class TreeExpandHelper {
private List<ExpandInfoNode> expandedElements;
private List<ExpandInfoNode> expandedTypes;
public TreeExpandHelper() {
expandedElements = new ArrayList<TreeExpandHelper.ExpandInfoNode>();
expandedTypes = new ArrayList<TreeExpandHelper.ExpandInfoNode>();
}
public void recordExpandState(DataModelMainPage mainPage) {
if (mainPage == null) {
return;
}
cleanCache();
TreeViewer elementsViewer = mainPage.getElementsViewer();
TreeViewer typesViewer = mainPage.getTypesViewer();
expandedElements = getExpandedNodes(elementsViewer.getExpandedTreePaths());
expandedTypes = getExpandedNodes(typesViewer.getExpandedTreePaths());
}
public void recoverExpandState(DataModelMainPage mainPage) {
if (mainPage == null) {
return;
}
Object[] expandedEntityElements = getExpandedEntityElements(mainPage);
mainPage.getElementsViewer().setExpandedElements(expandedEntityElements);
Object[] expandedTypeElements = getExpandedTypeElements(mainPage);
mainPage.getTypesViewer().setExpandedElements(expandedTypeElements);
cleanCache();
}
private List<ExpandInfoNode> getExpandedNodes(TreePath[] expandedElementPaths) {
TreePath[] expandedPaths = removeInvalidTreePaths(expandedElementPaths);
List<ExpandInfoNode> expanded = new ArrayList<ExpandInfoNode>();
ExpandInfoNode rootNode = null;
for (TreePath path : expandedPaths) {
int segmentCount = path.getSegmentCount();
Object firstSegment = path.getFirstSegment();
rootNode = ExpandInfoNode.create(getName(firstSegment), firstSegment.getClass().getName());
if (expanded.contains(rootNode)) {
rootNode = expanded.get(expanded.indexOf(rootNode));
} else {
expanded.add(rootNode);
}
for (int i = 1; i < segmentCount; i++) {
Object segment = path.getSegment(i);
ExpandInfoNode newNode = ExpandInfoNode.create(getName(segment), segment.getClass().getName());
if (rootNode.childs == null) {
rootNode.addChild(newNode);
} else {
if (rootNode.childs.contains(newNode)) {
newNode = rootNode.childs.get(rootNode.childs.indexOf(newNode));
} else {
rootNode.addChild(newNode);
}
}
rootNode = newNode;
}
}
return expanded;
}
private TreePath[] removeInvalidTreePaths(TreePath[] expandedElementPaths) {
Map<Integer, Set<TreePath>> pathMaps = new HashMap<Integer, Set<TreePath>>();
int maxSegmentCount = -1;
for (TreePath path : expandedElementPaths) {
int segmentCount = path.getSegmentCount();
Set<TreePath> pathSet = pathMaps.get(segmentCount);
if (pathSet == null) {
pathSet = new HashSet<TreePath>();
pathMaps.put(segmentCount, pathSet);
}
pathSet.add(path);
//
if (maxSegmentCount < segmentCount) {
maxSegmentCount = segmentCount;
}
}
Set<TreePath> roots = pathMaps.get(1);
if (roots == null || roots.size() == 0) {
return new TreePath[0];
}
// record TreePath by tree level
List<TreePath> paths = new ArrayList<TreePath>();
paths.addAll(roots);
for (int i = 2; i < maxSegmentCount + 1; i++) {
Set<TreePath> set = pathMaps.get(i);
if (set == null || set.size() == 0) {
break;
}
Set<TreePath> parents = pathMaps.get(i - 1);
Iterator<TreePath> iterator = set.iterator();
while (iterator.hasNext()) {
TreePath path = iterator.next();
if (parents.contains(path.getParentPath())) {
paths.add(path);
} else {
iterator.remove();
}
}
}
return paths.toArray(new TreePath[0]);
}
// ///
private Object[] getExpandedEntityElements(DataModelMainPage mainPage) {
TreeViewer elementsViewer = mainPage.getElementsViewer();
SchemaTreeContentProvider contentProvider = (SchemaTreeContentProvider) elementsViewer.getContentProvider();
Object[] xsdDeclarations = getChildren(contentProvider.getXsdSchema(), contentProvider);
List<Object> result = new ArrayList<Object>();//
Deque<ExpandInfoNode> nodeStack = new LinkedList<ExpandInfoNode>();//
Deque<Object> elementStack = new LinkedList<Object>();//
// record entities
Map<ExpandInfoNode, XSDElementDeclaration> expandedRoots = new HashMap<ExpandInfoNode, XSDElementDeclaration>();
for (Object obj : xsdDeclarations) {
if (obj instanceof XSDElementDeclaration) {
XSDElementDeclaration decl = (XSDElementDeclaration) obj;
String name = decl.getName();
for (ExpandInfoNode node : expandedElements) {
if (name.equals(node.name)) {
expandedRoots.put(node, decl);
result.add(decl);
nodeStack.add(node);// /
elementStack.add(decl);// /
break;
}
}
}
}
while (!nodeStack.isEmpty() && !elementStack.isEmpty()) {
ExpandInfoNode node = nodeStack.pollFirst();
Object element = elementStack.pollFirst();
List<ExpandInfoNode> nodes = node.childs;
Object[] elementChildren = getChildren(element, contentProvider);
if (nodes != null && nodes.size() > 0 && elementChildren != null) {
Map<ExpandInfoNode, Object> nodeElementPairs = getNodeElementPairs(elementChildren, nodes);
for (ExpandInfoNode node2 : nodeElementPairs.keySet()) {
nodeStack.add(node2);
elementStack.add(nodeElementPairs.get(node2));
result.add(nodeElementPairs.get(node2));
}
}
}
return result.toArray();
}
private Object[] getExpandedTypeElements(DataModelMainPage mainPage) {
TreeViewer typesViewer = mainPage.getTypesViewer();
SchemaTreeContentProvider contentProvider = (SchemaTreeContentProvider) typesViewer.getContentProvider();
Object[] xsdDeclarations = getChildren(contentProvider.getXsdSchema(), contentProvider);
List<Object> result = new ArrayList<Object>();//
Deque<ExpandInfoNode> nodeStack = new LinkedList<ExpandInfoNode>();//
Deque<Object> elementStack = new LinkedList<Object>();//
// record entities
Map<ExpandInfoNode, XSDTypeDefinition> expandedRoots = new HashMap<ExpandInfoNode, XSDTypeDefinition>();
for (Object obj : xsdDeclarations) {
XSDTypeDefinition type = (XSDTypeDefinition) obj;
String name = type.getName();
for (ExpandInfoNode node : expandedTypes) {
if (name.equals(node.name)) {
expandedRoots.put(node, type);
result.add(type);
nodeStack.add(node);// /
elementStack.add(type);// /
break;
}
}
}
while (!nodeStack.isEmpty() && !elementStack.isEmpty()) {
ExpandInfoNode node = nodeStack.pollFirst();
Object element = elementStack.pollFirst();
List<ExpandInfoNode> nodes = node.childs;
Object[] elementChildren = getChildren(element, contentProvider);
if (nodes != null && nodes.size() > 0 && elementChildren != null) {
Map<ExpandInfoNode, Object> nodeElementPairs = getNodeElementPairs(elementChildren, nodes);
for (ExpandInfoNode node2 : nodeElementPairs.keySet()) {
nodeStack.add(node2);
elementStack.add(nodeElementPairs.get(node2));
result.add(nodeElementPairs.get(node2));
}
}
}
return result.toArray();
}
private Object[] getChildren(Object parent, SchemaTreeContentProvider contentProvider) {
Object[] children = contentProvider.getChildren(parent);
return children;
}
private Map<ExpandInfoNode, Object> getNodeElementPairs(Object[] elementChildrens, List<ExpandInfoNode> nodes) {
Map<ExpandInfoNode, Object> pairs = new HashMap<ExpandInfoNode, Object>();
for (Object child : elementChildrens) {
for (ExpandInfoNode node : nodes) {
if (isSameXSDElement(child, node)) {
pairs.put(node, child);
}
}
}
return pairs;
}
private boolean isSameXSDElement(Object objA, ExpandInfoNode objB) {
if (objA != null && objB != null) {
objA = ExpandInfoNode.create(getName(objA), objA.getClass().getName());
return objB.equals(objA);
}
return false;
}
private String getName(Object objA) {
if (objA instanceof XSDElementDeclaration) {
XSDElementDeclaration decl = (XSDElementDeclaration) objA;
return decl.getName();
}
if (objA instanceof XSDModelGroup) {
XSDModelGroup goup = (XSDModelGroup) objA;
XSDParticle particle = (XSDParticle) goup.getContainer();
XSDComplexTypeDefinition complexTypeDefinition = (XSDComplexTypeDefinition) particle.getContainer();
String name = complexTypeDefinition.getName();
return name;
}
if (objA instanceof XSDModelGroupDefinition) {
XSDModelGroupDefinition goupDef = (XSDModelGroupDefinition) objA;
return goupDef.getName();
}
if (objA instanceof XSDParticle) {
XSDParticle particle = (XSDParticle) objA;
if (particle.getTerm() instanceof XSDElementDeclaration) {
XSDElementDeclaration decl = (XSDElementDeclaration) particle.getTerm();
return decl.getName();
}
}
if (objA instanceof XSDAnnotation) {
return null;
}
if (objA instanceof XSDIdentityConstraintDefinition) {
XSDIdentityConstraintDefinition constraint = (XSDIdentityConstraintDefinition) objA;
return constraint.getName();
}
if (objA instanceof XSDSimpleTypeDefinition) {
XSDSimpleTypeDefinition simpleDefine = (XSDSimpleTypeDefinition) objA;
return simpleDefine.getName();
}
if (objA instanceof XSDComplexTypeDefinition) {
XSDComplexTypeDefinition complexDefine = (XSDComplexTypeDefinition) objA;
return complexDefine.getName();
}
return null;
}
public void cleanCache() {
expandedElements.clear();
expandedTypes.clear();
}
// /////////////////
static class ExpandInfoNode {
public String name;
public String type;
public List<ExpandInfoNode> childs;
public static ExpandInfoNode create(String name, String type) {
return new ExpandInfoNode(name, type);
}
public ExpandInfoNode(String name, String type) {
this.name = name;
this.type = type;
}
public void addChild(ExpandInfoNode obj) {
if (childs == null) {
childs = new ArrayList<ExpandInfoNode>();
}
childs.add(obj);
}
public boolean hasChildren() {
if (childs == null || childs.size() == 0) {
return false;
}
return true;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof ExpandInfoNode) {
ExpandInfoNode node = (ExpandInfoNode) obj;
if (name != null) {
return name.equals(node.name) && type.equals(node.type);
} else {
return type.equals(node.type);
}
}
return false;
}
}
}