[157430] [outline] dtd outline view does not update when delete attribute
diff --git a/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/views/contentoutline/DTDTreeContentProvider.java b/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/views/contentoutline/DTDTreeContentProvider.java
index a6aa906..d399acb 100644
--- a/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/views/contentoutline/DTDTreeContentProvider.java
+++ b/bundles/org.eclipse.wst.dtd.ui/src/org/eclipse/wst/dtd/ui/views/contentoutline/DTDTreeContentProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2001, 2006 IBM Corporation and others.
+ * Copyright (c) 2001, 2011 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
@@ -149,53 +149,10 @@
 	}
 
 	public Object getParent(Object element) {
+		List parents = getParents(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();
+		if(parents.size() > 0) {
+			parent = parents.get(0);
 		}
 		return parent;
 	}
@@ -242,66 +199,13 @@
 		return true;// !nodeList.getListType().equals(DTDRegionTypes.ATTLIST_TAG);
 	}
 
+	/**
+	 * <p>If a node changed then refresh the tree for that node</p>
+	 * 
+	 * @see org.eclipse.wst.dtd.core.internal.event.IDTDFileListener#nodeChanged(org.eclipse.wst.dtd.core.internal.DTDNode)
+	 */
 	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());
-		}
+		refreshTree(node);
 	}
 
 	public void nodesAdded(NodesEvent event) {
@@ -315,45 +219,8 @@
 				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);
-						}
-					});
-				}
-			}
+			//update the tree
+			refreshTree(event);
 
 			Iterator iter = event.getNodes().iterator();
 			List newSelection = new ArrayList();
@@ -380,6 +247,8 @@
 			}
 		}
 
+		//update the tree
+		refreshTree(event);
 	}
 
 	/**
@@ -395,4 +264,139 @@
 			logicalNodeLists = null;
 		}
 	}
+	
+	/**
+	 * <p>Used to update the tree after a node event such as a node added or removed.</p>
+	 * @param event the {@link NodesEvent} that caused the tree to need updating
+	 */
+	private void refreshTree(NodesEvent event) {
+		for (Iterator it = event.getNodes().iterator(); it.hasNext();) {
+			Object node = it.next();
+			this.refreshTree(node);
+			
+		}
+	}
+	
+	/**
+	 * <p>Refreshes the tree from the parents of the given node.</p>
+	 * @param node refresh the tree from the parents of this node
+	 */
+	private void refreshTree(Object node) {
+		List parents = getParents(node);
+		if(parents.size() > 0) {
+			for(int p = 0; p < parents.size(); ++p) {
+				final Object parent = parents.get(p);
+			
+				// 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) fViewer).insert(parent, node, i);
+							break;
+						}
+					}
+				}
+				
+				this.refreshTreeNode(parent, true);
+			}
+		}
+	}
+	
+	/**
+	 * @param element get the tree parents of this element
+	 * @return {@link List} of parents of the given element
+	 */
+	private List getParents(Object element) {
+		List parents = new ArrayList();
+		
+		Object parent = null;
+		if (element instanceof DTDNode) {
+			DTDNode node = (DTDNode) element;
+			if (element instanceof Attribute) {
+				parent = node.getParentNode();
+				if (parent != null && parent instanceof AttributeList) {
+					parents.addAll(getElementParentsOfAttributeList((AttributeList)parent));
+				}
+			} else if(element instanceof AttributeList) {
+				parents.addAll(getElementParentsOfAttributeList((AttributeList)element));
+			}
+
+			// if showing in the logical order, return the IndexedNodeList
+			// acting as a parent in the tree
+			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)) {
+							parents.add(indexedNodeLists[i]);
+						}
+					}
+				}
+			}
+			
+			//try and get the simple parent
+			parent = ((DTDNode) element).getParentNode();
+			if(parent != null) {
+				parents.add(parent);
+			}
+			
+			//if no parents found must be new nodes so refresh from root
+			if(parents.size() == 0) {
+				parents.add(((DTDModelImpl) fInputObject).getDTDFile());
+			}
+		}else if (element instanceof NodeList && fInputObject instanceof DTDModelImpl) {
+			parents.add(((DTDModelImpl) fInputObject).getDTDFile());
+		}
+		
+		return parents;
+	}
+	
+	/**
+	 * @param attList get the element parents of the given {@link AttributeList}
+	 * @return the element parents of the given {@link AttributeList}, if no parents
+	 * can be found the list contains the DTD file element
+	 */
+	private List getElementParentsOfAttributeList(AttributeList attList) {
+		List parents = new ArrayList();
+		Iterator iterAttList = attList.getDTDFile().getNodes().iterator();
+		while (iterAttList.hasNext()) {
+			DTDNode currentNode = (DTDNode) iterAttList.next();
+			if (currentNode instanceof Element &&
+					currentNode.getName().equals(attList.getName())) {
+
+				parents.add(currentNode);
+			}
+		}
+		
+		if(parents.size() == 0) {
+			parents.add(((DTDModelImpl) fInputObject).getDTDFile());
+		}
+		
+		return parents;
+	}
+	
+	/**
+	 * <p>Executes a refresh on the {@link AbstractTreeViewer} for the given
+	 * node</p>
+	 * 
+	 * @param node refresh the tree for this node
+	 * @param updateLabels <code>true</code> to update the labels on the tree,
+	 * <code>false</code> otherwise.
+	 */
+	private void refreshTreeNode(final Object node, final boolean updateLabels) {
+		fViewer.getControl().getDisplay().asyncExec(new Runnable() {
+			public void run() {
+				if (!fViewer.getControl().isDisposed()) {
+					if(node != null) {
+						((AbstractTreeViewer) fViewer).refresh(node, updateLabels);
+					} else {
+						((AbstractTreeViewer) fViewer).refresh(updateLabels);
+					}
+				}
+			}
+		});
+	}
 }