blob: a6aa906b4ead6d462b9013bc4f0bf472de7af268 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.dtd.ui.views.contentoutline;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.wst.dtd.core.internal.Attribute;
import org.eclipse.wst.dtd.core.internal.AttributeList;
import org.eclipse.wst.dtd.core.internal.Comment;
import org.eclipse.wst.dtd.core.internal.DTDFile;
import org.eclipse.wst.dtd.core.internal.DTDNode;
import org.eclipse.wst.dtd.core.internal.Element;
import org.eclipse.wst.dtd.core.internal.Entity;
import org.eclipse.wst.dtd.core.internal.NodeList;
import org.eclipse.wst.dtd.core.internal.Notation;
import org.eclipse.wst.dtd.core.internal.ParameterEntityReference;
import org.eclipse.wst.dtd.core.internal.document.DTDModelImpl;
import org.eclipse.wst.dtd.core.internal.event.IDTDFileListener;
import org.eclipse.wst.dtd.core.internal.event.NodesEvent;
class DTDTreeContentProvider implements ITreeContentProvider, IDTDFileListener {
private Object fInputObject;
protected Viewer fViewer;
// A cached set of IndexedNodeLists, required for getParent to return the
// correct instances mapping to TreeItems
protected Object[] logicalNodeLists = null;
private boolean showLogicalOrder = false;
public DTDTreeContentProvider() {
super();
}
public void dispose() {
fViewer = null;
}
private void expandToNode(DTDNode node) {
DTDFile dtdFile = node.getDTDFile();
// first expand the root
AbstractTreeViewer viewer = (AbstractTreeViewer) fViewer;
viewer.expandToLevel(dtdFile, 1);
NodeList listToExpand = null;
if (node instanceof Element || node instanceof ParameterEntityReference) {
listToExpand = dtdFile.getElementsAndParameterEntityReferences();
}
else if (node instanceof Notation) {
listToExpand = dtdFile.getNotations();
}
else if (node instanceof Entity) {
listToExpand = dtdFile.getEntities();
}
else if (node instanceof Comment) {
listToExpand = dtdFile.getComments();
}
if (listToExpand != null) {
viewer.expandToLevel(listToExpand, 1);
}
viewer.expandToLevel(node, 0);
}
public Object[] getChildren(Object parentElement) {
// return the lists of nodes when in logical order mode, all the Nodes
// otherwise
if (parentElement instanceof DTDFile) {
if (isShowLogicalOrder()) {
// return the visible node lists
if (logicalNodeLists == null) {
Iterator nodeLists = ((DTDFile) parentElement).getNodeLists().iterator();
List visibleLists = new ArrayList(7);
while (nodeLists.hasNext()) {
NodeList list = (NodeList) nodeLists.next();
if (isVisibleNodeList(list)) {
visibleLists.add(list);
}
}
logicalNodeLists = visibleLists.toArray();
}
return logicalNodeLists;
}
else {
// return the visible nodes
List allNodes = ((DTDFile) parentElement).getNodes();
List visibleNodes = new ArrayList(allNodes.size());
for (int i = 0; i < allNodes.size(); i++) {
Object o = allNodes.get(i);
if (isVisibleNode(o)) {
visibleNodes.add(o);
}
}
return visibleNodes.toArray();
}
}
else if (parentElement instanceof NodeList) {
return ((NodeList) parentElement).getNodes().toArray();
}
else if (parentElement instanceof Element) {
// always group the attributes directly under the element
Object[] children = ((DTDNode) parentElement).getChildren();
List attributes = ((Element) parentElement).getElementAttributes();
Object[] logicalChildren = new Object[children.length + attributes.size()];
int index = 0;
for (index = 0; index < children.length; index++) {
logicalChildren[index] = children[index];
}
for (Iterator iter = attributes.iterator(); iter.hasNext();) {
logicalChildren[index++] = iter.next();
}
return logicalChildren;
}
else if (parentElement instanceof DTDNode) {
return ((DTDNode) parentElement).getChildren();
}
return Collections.EMPTY_LIST.toArray();
}
public Object[] getElements(java.lang.Object inputElement) {
Object[] elements = null;
// Always show the DTDFile "node"
if (inputElement instanceof DTDModelImpl) {
elements = new Object[]{((DTDModelImpl) inputElement).getDTDFile()};
}
if (elements == null) {
elements = new Object[0];
}
return elements;
}
public Object getParent(Object element) {
Object parent = null;
if (element instanceof DTDNode) {
DTDNode node = (DTDNode) element;
if (element instanceof Attribute) {
// then we must say that the element with the same name
// as our attribute's parent attributelist is our parent
parent = node.getParentNode();
if (parent != null && parent instanceof AttributeList) {
return getParent(parent);
}
}
if (element instanceof AttributeList) {
// then we must say that the element with the same name
// as our attributelist is our parent
String attListName = ((AttributeList) element).getName();
Iterator iter = node.getDTDFile().getElementsAndParameterEntityReferences().getNodes().iterator();
while (iter.hasNext() && parent == null) {
DTDNode currentNode = (DTDNode) iter.next();
if (currentNode instanceof Element && currentNode.getName().equals(attListName)) {
parent = currentNode;
}
}
}
if (parent == null) {
parent = ((DTDNode) element).getParentNode();
}
// if showing in the logical order, return the IndexedNodeList
// acting as the parent in the tree
if (parent == null) {
if (isShowLogicalOrder()) {
Object[] indexedNodeLists = getChildren(((DTDModelImpl) fInputObject).getDTDFile());
for (int i = 0; i < indexedNodeLists.length && parent == null; i++) {
if (indexedNodeLists[i] instanceof NodeList) {
if (((NodeList) indexedNodeLists[i]).getNodes().contains(element))
parent = indexedNodeLists[i];
}
}
}
else {
parent = ((DTDModelImpl) fInputObject).getDTDFile();
}
}
}
else if (element instanceof NodeList && fInputObject instanceof DTDModelImpl) {
parent = ((DTDModelImpl) fInputObject).getDTDFile();
}
return parent;
}
public boolean hasChildren(Object element) {
Object[] children = getChildren(element);
return children.length > 0;
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
fViewer = viewer;
if (fInputObject instanceof DTDModelImpl) {
((DTDModelImpl) fInputObject).getDTDFile().removeDTDFileListener(this);
}
fInputObject = newInput;
if (fInputObject instanceof DTDModelImpl) {
((DTDModelImpl) fInputObject).getDTDFile().addDTDFileListener(this);
}
}
/**
* Get the value of showLogicalOrder.
*
* @return value of showLogicalOrder.
*/
public boolean isShowLogicalOrder() {
return showLogicalOrder;
}
private boolean isVisibleNode(Object o) {
if (o instanceof AttributeList) {
return false;
}
return true;
}
private boolean isVisibleNodeList(NodeList nodeList) {
/*
* All NodesLists should be visible because you can momentarily have
* an ATTLIST (for example) without a corresponding ELEMENT
* declaration
*/
return true;// !nodeList.getListType().equals(DTDRegionTypes.ATTLIST_TAG);
}
public void nodeChanged(final DTDNode node) {
if (fViewer instanceof StructuredViewer) {
// System.out.println("node changed notified");
// System.out.println("selection before = " +
// ((StructuredViewer)view).getSelection());
if (node instanceof AttributeList && isShowLogicalOrder()) {
// in this case, we are showing attributes under the element.
// refresh the element object instead
Iterator iter = node.getDTDFile().getNodes().iterator();
while (iter.hasNext()) {
DTDNode currentNode = (DTDNode) iter.next();
if (currentNode.getName().equals(node.getName()) && currentNode instanceof Element) {
((StructuredViewer) fViewer).refresh(currentNode, true);
}
} // end of while ()
}
else {
// do standard stuff
fViewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (fViewer.getControl().isDisposed())
return;
if (node.getParentNode() != null) {
((StructuredViewer) fViewer).refresh(node.getParentNode(), true);
}
((StructuredViewer) fViewer).refresh(node, true);
}
});
}
if (node instanceof Attribute) {
fViewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (fViewer.getControl().isDisposed())
return;
/*
* go from the attribute to its list and then owning element
* so we refresh the tree item there as well
*/
Object attrList = node.getParentNode();
if (attrList != null && attrList instanceof AttributeList) {
String attListName = ((AttributeList) attrList).getName();
Iterator iter = node.getDTDFile().getElementsAndParameterEntityReferences().getNodes().iterator();
Object parent = null;
while (iter.hasNext() && parent == null) {
DTDNode currentNode = (DTDNode) iter.next();
if (currentNode instanceof Element && currentNode.getName().equals(attListName)) {
parent = currentNode;
}
}
if (parent != null) {
((StructuredViewer) fViewer).refresh(parent, true);
}
}
}
});
}
// System.out.println("selection after = " +
// ((StructuredViewer)view).getSelection());
}
}
public void nodesAdded(NodesEvent event) {
if (fViewer instanceof AbstractTreeViewer) {
StructuredViewer viewer = (StructuredViewer) fViewer;
ISelection selection = viewer.getSelection();
Object firstObj = (!selection.isEmpty() && selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null;
DTDNode oldSelectedNode = null;
if (firstObj instanceof DTDNode) {
oldSelectedNode = (DTDNode) firstObj;
}
final AbstractTreeViewer abstractTreeViewer = (AbstractTreeViewer) fViewer;
for (Iterator it = event.getNodes().iterator(); it.hasNext();) {
Object node = it.next();
final Object parent = getParent(node);
// Bug 111100 - If it is a top level node (ie. parent is a
// DTDFile),
// insert the node directly to improve performance
if (parent instanceof DTDFile) {
Object[] objs = getChildren(parent);
for (int i = 0; i < objs.length; i++) {
if (objs[i] == node) {
abstractTreeViewer.insert(parent, node, i);
break;
}
}
}
// If the parent node is not a DTDFile, just refresh the
// parent for now
else if (parent != null) {
fViewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (fViewer.getControl().isDisposed())
return;
abstractTreeViewer.refresh(parent, true);
}
});
}
// You should never reach this block, if you do, just refresh
// the whole tree
else {
fViewer.getControl().getDisplay().asyncExec(new Runnable() {
public void run() {
if (fViewer.getControl().isDisposed())
return;
abstractTreeViewer.refresh(true);
}
});
}
}
Iterator iter = event.getNodes().iterator();
List newSelection = new ArrayList();
while (iter.hasNext()) {
DTDNode node = (DTDNode) iter.next();
if (oldSelectedNode == null || node.getStructuredDTDDocumentRegion() != oldSelectedNode.getStructuredDTDDocumentRegion() || node.getStartOffset() != oldSelectedNode.getStartOffset() || node.getEndOffset() != oldSelectedNode.getEndOffset()) {
// add to selection
newSelection.add(node);
expandToNode(node);
}
}
if (newSelection.size() > 0) {
viewer.setSelection(new StructuredSelection(newSelection));
}
}
}
public void nodesRemoved(NodesEvent event) {
if (fViewer instanceof AbstractTreeViewer) {
AbstractTreeViewer abstractTreeViewer = (AbstractTreeViewer) fViewer;
for (Iterator iter = event.getNodes().iterator(); iter.hasNext();) {
abstractTreeViewer.remove(iter.next());
}
}
}
/**
* Set the value of showLogicalOrder.
*
* @param value
* Value to assign to showLogicalOrder.
*/
public void setShowLogicalOrder(boolean value) {
this.showLogicalOrder = value;
if (!value) {
// if not using logical order, lose the cached lists
logicalNodeLists = null;
}
}
}