NEW - bug 200066: [pde viz] Highlight cycles in Graph
https://bugs.eclipse.org/bugs/show_bug.cgi?id=200066
NEW - bug 200196: [pde viz] Use a managed form for the PDE Viz View
https://bugs.eclipse.org/bugs/show_bug.cgi?id=200196
RESOLVED - bug 200034: [pde viz] Indicate plug-ins which cannot be resolved
https://bugs.eclipse.org/bugs/show_bug.cgi?id=200034
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/.classpath b/visualization/plugins/org.eclipse.pde.visualization.dependency/.classpath
index 039f2bb..ce73933 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/.classpath
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/.classpath
@@ -1,9 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src"/>
-	<classpathentry exported="true" kind="lib" path="org.eclipse.draw2d_3.2.100.200708141030.jar"/>
-	<classpathentry exported="true" kind="lib" path="org.eclipse.mylyn.zest.core_0.5.0.200708141030.jar"/>
-	<classpathentry exported="true" kind="lib" path="org.eclipse.mylyn.zest.layouts_0.5.0.200708141030.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="output" path="bin"/>
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/META-INF/MANIFEST.MF b/visualization/plugins/org.eclipse.pde.visualization.dependency/META-INF/MANIFEST.MF
index 909a371..1dd6471 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/META-INF/MANIFEST.MF
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/META-INF/MANIFEST.MF
@@ -9,10 +9,10 @@
  org.eclipse.pde.ui,
  org.eclipse.ui.forms,
  org.eclipse.equinox.launcher,
- org.eclipse.core.resources
+ org.eclipse.core.resources,
+ org.eclipse.mylyn.zest.core,
+ org.eclipse.mylyn.zest.layouts,
+ org.eclipse.draw2d
 Eclipse-LazyStart: true
-Bundle-ClassPath: .,
- org.eclipse.draw2d_3.2.100.200708141030.jar,
- org.eclipse.mylyn.zest.core_0.5.0.200708141030.jar,
- org.eclipse.mylyn.zest.layouts_0.5.0.200708141030.jar
+Bundle-ClassPath: .
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/build.properties b/visualization/plugins/org.eclipse.pde.visualization.dependency/build.properties
index 4529243..66cf6e9 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/build.properties
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/build.properties
@@ -1,10 +1,7 @@
 bin.includes = META-INF/,\
                plugin.xml,\
                icons/,\
-               .,\
-               org.eclipse.draw2d_3.2.100.200708141030.jar,\
-               org.eclipse.mylyn.zest.core_0.5.0.200708141030.jar,\
-               org.eclipse.mylyn.zest.layouts_0.5.0.200708141030.jar
+               .
 src.includes = src/,\
                plugin.xml,\
                META-INF/,\
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/Activator.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/Activator.java
index c0c0119..e2f3931 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/Activator.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/Activator.java
@@ -31,6 +31,7 @@
 	public static final String BACKWARD_ENABLED = "icons/obj16/backward_enabled.gif";
 	public static final String SNAPSHOT = "icons/obj16/snapshot.gif";
 	public static final String SAVEEDIT = "icons/obj16/save_edit.gif";
+	public static final String REQ_PLUGIN_OBJ ="icons/obj16/req_plugins_obj.gif";
 	
 	public static final String PLUGIN_OBJ = "plugin_obj";
 
@@ -54,6 +55,7 @@
 		addImage(BACKWARD_ENABLED);
 		addImage(SNAPSHOT);
 		addImage(SAVEEDIT);
+		addImage(REQ_PLUGIN_OBJ);
 		this.getImageRegistry().put(PLUGIN_OBJ, PDEPluginImages.DESC_PLUGIN_OBJ);
 	}
 	
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AbstractVisualizationLabelProvider.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AbstractVisualizationLabelProvider.java
index a253894..8379a3e 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AbstractVisualizationLabelProvider.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AbstractVisualizationLabelProvider.java
@@ -21,8 +21,8 @@
 import org.eclipse.mylyn.zest.core.viewers.IEntityStyleProvider;
 import org.eclipse.mylyn.zest.core.widgets.ZestStyles;
 import org.eclipse.osgi.service.resolver.BundleDescription;
-import org.eclipse.pde.core.plugin.PluginRegistry;
-import org.eclipse.pde.internal.ui.PDELabelProvider;
+import org.eclipse.osgi.service.resolver.BundleSpecification;
+import org.eclipse.pde.internal.ui.views.dependencies.DependenciesLabelProvider;
 import org.eclipse.pde.visualization.dependency.Activator;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Image;
@@ -71,7 +71,7 @@
 	protected BundleDescription pinnedNode = null;
 	private GraphViewer viewer;
 	private boolean showVersionNumber = false;
-	private PDELabelProvider pdeLabelProvider = null;
+	private DependenciesLabelProvider pdeLabelProvider = null;
 
 	/**
 	 * Create a new Abstract Visualization Label Provider
@@ -82,7 +82,7 @@
 	 *            is used to maintain state between the old one and the new one.
 	 */
 	public AbstractVisualizationLabelProvider(GraphViewer viewer, AbstractVisualizationLabelProvider currentLabelProvider) {
-		this.pdeLabelProvider = new PDELabelProvider();
+		this.pdeLabelProvider = new DependenciesLabelProvider(true);
 		this.viewer = viewer;
 		if (currentLabelProvider != null) {
 			this.showVersionNumber = currentLabelProvider.showVersionNumber;
@@ -98,9 +98,18 @@
 		if (element.getClass() == EntityConnectionData.class) {
 			return null;
 		}
+		
+		if ( element instanceof BundleDescription || element instanceof BundleSpecification) {
+			return pdeLabelProvider.getImage(element);
+		}
+		/*
 		if ( element instanceof BundleDescription ) {
 			return pdeLabelProvider.getImage(PluginRegistry.findModel((BundleDescription)element));
 		}
+		else if ( element instanceof BundleSpecification) {
+			return pdeLabelProvider.getImage(element);
+		}
+		*/
 		return Activator.getDefault().getImageRegistry().get(Activator.PLUGIN_OBJ);
 	}
 
@@ -113,6 +122,10 @@
 			}
 			return bundleDescription.getName();
 		}
+		else if  ( element instanceof BundleSpecification ) {
+			BundleSpecification bundleSpecification = (BundleSpecification) element;
+			return bundleSpecification.getName();
+		}
 		return "";
 	}
 
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AnalysisUtil.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AnalysisUtil.java
index 1193143..168dcee 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AnalysisUtil.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/AnalysisUtil.java
@@ -30,7 +30,7 @@
  */
 public class AnalysisUtil {
 
-	public static BundleDescription[] getPath(BundleDescription root, BundleDescription bundle) {
+	public static BundleDescription[] getPath(Object root, Object bundle) {
 		LinkedList q = new LinkedList();
 		Set orderedSet = new HashSet();
 		LinkedList orderedList = new LinkedList();
@@ -48,7 +48,7 @@
 	}
 
 	private static void buildQueue(BundleDescription root, LinkedList q) {
-		BundleDescription[] descriptions = getDependencies(root);
+		Object[] descriptions = getDependencies(root);
 		if (descriptions == null || descriptions.length == 0) {
 			return;
 		}
@@ -57,7 +57,7 @@
 		}
 	}
 
-	public static BundleDescription[] modifiedDijkstra(LinkedList q, BundleDescription s, BundleDescription t) {
+	public static BundleDescription[] modifiedDijkstra(LinkedList q, Object s, Object t) {
 		HashMap previous = new HashMap();
 		HashMap dValues = new HashMap();
 		for (Iterator iter = q.iterator(); iter.hasNext();) {
@@ -66,14 +66,14 @@
 		dValues.put(s, new Integer(0));
 
 		while (!q.isEmpty()) {
-			BundleDescription head = (BundleDescription) q.remove(0);
-			BundleDescription[] outgoing = getDependencies(head);
+			Object head = q.remove(0);
+			Object[] outgoing = getDependencies(head);
 			if (outgoing == null) {
-				// @tag PDE bug : I guess null in my array of dependencies 
+				// @tag PDE bug : I get null in my array of dependencies 
 				continue;
 			}
 			for (int i = 0; i < outgoing.length; i++) {
-				BundleDescription v = outgoing[i];
+				Object v = outgoing[i];
 				if (((Integer) dValues.get(head)).intValue() + 1 < ((Integer) dValues.get(v)).intValue()) {
 					previous.put(v, head);
 					dValues.put(v, new Integer(((Integer) dValues.get(head)).intValue() + 1));
@@ -81,10 +81,10 @@
 			}
 		}
 		LinkedList path = new LinkedList();
-		BundleDescription currentNode = t;
+		Object currentNode = t;
 		while (previous.containsKey(currentNode)) {
 			path.add(currentNode);
-			currentNode = (BundleDescription) previous.get(currentNode);
+			currentNode = previous.get(currentNode);
 		}
 		path.add(currentNode);
 		return (BundleDescription[]) path.toArray(new BundleDescription[path.size()]);
@@ -107,11 +107,11 @@
 	 * 
 	 * @return
 	 */
-	public static BundleDescription[] getAllCallers(BundleDescription bundle, BundleDescription[] bundles) {
+	public static BundleDescription[] getAllCallers(BundleDescription bundle, Object[] bundles) {
 		HashSet callers = new HashSet();
 		for (int i = 0; i < bundles.length; i++) {
 			HashSet hashSet = new HashSet();
-			hashSet.addAll(Arrays.asList(getPrerequisites(new BundleDescription[] { bundles[i] })));
+			hashSet.addAll(Arrays.asList(getPrerequisites(new Object[] { bundles[i] })));
 			if (hashSet.contains(bundle)) {
 				callers.add(bundles[i]);
 			}
@@ -119,7 +119,7 @@
 		return (BundleDescription[]) callers.toArray(new BundleDescription[callers.size()]);
 	}
 
-	public static BundleDescription[] getPrerequisites(BundleDescription[] bundles) {
+	public static Object[] getPrerequisites(Object[] bundles) {
 		if (bundles == null || bundles.length == 0) {
 			return new BundleDescription[0];
 		}
@@ -127,7 +127,7 @@
 		for (int i = 0; i < bundles.length; i++) {
 			addPrerequisites(bundles[i], reachable);
 		}
-		return (BundleDescription[]) reachable.toArray(new BundleDescription[reachable.size()]);
+		return reachable.toArray(new Object[reachable.size()]);
 	}
 
 	private static Collection getExportedDescription(BundleDescription element, ExportPackageDescription[] exportedPackages) {
@@ -142,36 +142,37 @@
 	}
 
 	
-	public static BundleDescription[] getDependencies(BundleDescription bundle) {
+	public static Object[] getDependencies(Object bundle) {
 
-		if (bundle == null) {
+		if (bundle == null || bundle instanceof BundleSpecification) {
 			return null;
 		}
+		BundleDescription bundleDescription = (BundleDescription) bundle;
 
-		Collection c = AnalysisUtil.getDescription(bundle.getRequiredBundles());
-		c.addAll(getExportedDescription(bundle, bundle.getResolvedImports()));
+		Collection c = AnalysisUtil.getDescription(bundleDescription.getRequiredBundles());
+		c.addAll(getExportedDescription(bundleDescription, bundleDescription.getResolvedImports()));
 		/*
 		 * Iterator iterator = c.iterator(); while (iterator.hasNext() ) { if (
 		 * iterator.next() == null ) iterator.remove(); }
 		 */
 
-		return (BundleDescription[]) c.toArray(new BundleDescription[c.size()]);
+		return c.toArray(new Object[c.size()]);
 	}
 
-	private static void addPrerequisites(BundleDescription bundle, Set reachable) {
+	private static void addPrerequisites(Object bundle, Set reachable) {
 		if (reachable.contains(bundle)) {
 			return;
 		}
 		reachable.add(bundle);
 
-		BundleDescription[] dependencies = getDependencies(bundle);
+		Object[] dependencies = getDependencies(bundle);
 		for (int i = 0; i < dependencies.length; i++) {
-			if (dependencies[i] == null) {
-				//@tag PDE bug : I get null in my array of dependencies
-				//               This means that a supplier could not be found (constraint invalid)
-				continue;
+			if (dependencies[i] instanceof BundleSpecification ) {
+				reachable.add(dependencies[i]);
 			}
-			addPrerequisites(dependencies[i], reachable);
+			else {
+				addPrerequisites(dependencies[i], reachable);
+			}
 		}
 	}
 
@@ -179,7 +180,13 @@
 		ArrayList descriptionList = new ArrayList();
 		for (int i = 0; i < specifications.length; i++) {
 			BundleSpecification specification = specifications[i];
-			descriptionList.add(specification.getSupplier());
+			if ( specification.getSupplier() == null ) {
+				// We can't get a description, so just keep the bundle specification
+				descriptionList.add(specification);
+			}
+			else {
+				descriptionList.add(specification.getSupplier());
+			}
 		}
 		return descriptionList;
 	}
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/GraphContentProvider.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/GraphContentProvider.java
index 987c68b..a4130ab 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/GraphContentProvider.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/GraphContentProvider.java
@@ -23,7 +23,7 @@
 
 	BundleDescription currentBundle = null;
 
-	private BundleDescription[] getDependencies(BundleDescription bundle) {
+	private Object[] getDependencies(BundleDescription bundle) {
 		if (bundle != null) {
 			return AnalysisUtil.getPrerequisites(new BundleDescription[] { currentBundle });
 		}
@@ -31,8 +31,7 @@
 	}
 
 	public Object[] getConnectedTo(Object entity) {
-		BundleDescription e = (BundleDescription) entity;
-		return AnalysisUtil.getDependencies(e);
+		return AnalysisUtil.getDependencies(entity);
 	}
 
 	public Object[] getElements(Object inputElement) {
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/HighlightDependencyLableProvider.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/HighlightDependencyLableProvider.java
index b3af076..724dc91 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/HighlightDependencyLableProvider.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/HighlightDependencyLableProvider.java
@@ -14,7 +14,6 @@
 
 import org.eclipse.mylyn.zest.core.viewers.EntityConnectionData;
 import org.eclipse.mylyn.zest.core.viewers.GraphViewer;
-import org.eclipse.osgi.service.resolver.BundleDescription;
 
 /**
  * 
@@ -30,7 +29,7 @@
 	protected void calculateInterestingDependencies(HashSet interestingRels, HashSet interestingEntities) {
 
 		if (getSelected() != null) {
-			BundleDescription[] descriptions = AnalysisUtil.getDependencies(this.getSelected());
+			Object[] descriptions = AnalysisUtil.getDependencies(this.getSelected());
 			for (int i = 0; i < descriptions.length; i++) {
 				EntityConnectionData entityConnectionData = new EntityConnectionData(this.getSelected(), descriptions[i]);
 				interestingRels.add(entityConnectionData);
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/PluginVisualizationView.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/PluginVisualizationView.java
index 3e35c8e..964b500 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/PluginVisualizationView.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/PluginVisualizationView.java
@@ -22,6 +22,7 @@
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.viewers.DoubleClickEvent;
 import org.eclipse.jface.viewers.IDoubleClickListener;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -44,9 +45,14 @@
 import org.eclipse.mylyn.zest.layouts.algorithms.HorizontalShift;
 import org.eclipse.mylyn.zest.layouts.algorithms.TreeLayoutAlgorithm;
 import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.pde.core.plugin.IPluginModel;
 import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+import org.eclipse.pde.internal.core.builders.DependencyLoop;
+import org.eclipse.pde.internal.core.builders.DependencyLoopFinder;
 import org.eclipse.pde.internal.ui.wizards.PluginSelectionDialog;
 import org.eclipse.pde.visualization.dependency.Activator;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
@@ -55,8 +61,11 @@
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.IWorkbenchActionConstants;
-import org.eclipse.ui.forms.widgets.Form;
+import org.eclipse.ui.forms.IFormColors;
+import org.eclipse.ui.forms.IMessage;
+import org.eclipse.ui.forms.ManagedForm;
 import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
 import org.eclipse.ui.part.ViewPart;
 
 /**
@@ -76,7 +85,8 @@
 public class PluginVisualizationView extends ViewPart implements IZoomableWorkbenchPart {
 
 	private FormToolkit toolKit = null;
-	private Form form = null;
+	private ScrolledForm form = null;
+	private ManagedForm managedForm = null;
 	private GraphViewer viewer;
 	private Action focusDialogAction;
 	private Action focusAction;
@@ -108,10 +118,21 @@
 	 */
 	public void createPartControl(Composite parent) {
 
-		toolKit = new FormToolkit(parent.getDisplay());
+		toolKit = new FormToolkit(parent.getDisplay()) {
+			public ScrolledForm createScrolledForm(Composite parent) {
+				ScrolledForm form = new ScrolledForm(parent, SWT.NONE);
+				form.setExpandHorizontal(true);
+				form.setExpandVertical(true);
+				form.setBackground(getColors().getBackground());
+				form.setForeground(getColors().getColor(IFormColors.TITLE));
+				form.setFont(JFaceResources.getHeaderFont());
+				return form;
+			}
+		};
 		VisualizationForm visualizationForm = new VisualizationForm(parent, toolKit, this);
 		viewer = visualizationForm.getGraphViewer();
 		form = visualizationForm.getForm();
+		managedForm = visualizationForm.getManagedForm();
 
 		this.contentProvider = new GraphContentProvider();
 		this.currentLabelProvider = new HighlightDependencyLableProvider(this.viewer, null);
@@ -120,31 +141,32 @@
 		viewer.setInput(null);
 		viewer.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
 		viewer.setLayoutAlgorithm(new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING, new LayoutAlgorithm[] { new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }));
+		//viewer.setLayoutAlgorithm(new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING, new LayoutAlgorithm[] { new DirectedGraphLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }));
 
 		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
 
 			public void selectionChanged(SelectionChangedEvent event) {
 				Object selectedElement = ((IStructuredSelection) event.getSelection()).getFirstElement();
-				if ( selectedElement instanceof EntityConnectionData ) {
+				if (selectedElement instanceof EntityConnectionData) {
 					return;
 				}
 				PluginVisualizationView.this.selectionChanged(selectedElement);
 			}
 		});
-		
+
 		viewer.addDoubleClickListener(new IDoubleClickListener() {
 
 			public void doubleClick(DoubleClickEvent event) {
 				// On a double click we now focus on that node.
 				// See bug: 172627: [pde viz] double-clicking on a node should implicitly focus on it.
 				//    https://bugs.eclipse.org/bugs/show_bug.cgi?id=172627
-				
+
 				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
-				if ( selection.size() < 1 ) {
+				if (selection.size() < 1) {
 					return;
 				}
 				Object selectedElement = selection.getFirstElement();
-				if ( selectedElement instanceof BundleDescription) {
+				if (selectedElement instanceof BundleDescription) {
 					focusOn((BundleDescription) selectedElement, true);
 					// When a new plug-in is selected, disable the forward action.
 					// The forward action only stores history when the back button was used (much like a browser)
@@ -152,7 +174,7 @@
 					forwardAction.setEnabled(false);
 				}
 			}
-			
+
 		});
 		toolbarZoomContributionViewItem = new ZoomContributionViewItem(this);
 		contextZoomContributionViewItem = new ZoomContributionViewItem(this);
@@ -185,12 +207,12 @@
 			return;
 		}
 
-		StructuredSelection selection =  ((StructuredSelection)viewer.getSelection()); 
-		if ( selection != null ) {
+		StructuredSelection selection = ((StructuredSelection) viewer.getSelection());
+		if (selection != null) {
 			viewer.setSelection(new StructuredSelection());
 			this.selectionChanged(null);
 		}
-		
+
 		if (dependencyPath) {
 			// If dependencyPath is set to true set the
 			// ShortestPathDependencyAnalyis label provider
@@ -208,15 +230,14 @@
 			viewer.setLabelProvider(this.currentLabelProvider);
 			//viewer.refresh();
 			//viewer.setInput(this.currentBundle);
-			
 
 		} else if (!dependencyPath && !(currentLabelProvider instanceof HighlightDependencyLableProvider)) {
 			this.currentLabelProvider = new HighlightDependencyLableProvider(this.viewer, (AbstractVisualizationLabelProvider) this.currentLabelProvider);
 			viewer.setLabelProvider(this.currentLabelProvider);
 
 		}
-		
-		if ( selection != null ) {
+
+		if (selection != null) {
 			viewer.setSelection(selection);
 		}
 
@@ -226,9 +247,9 @@
 		if (viewer.getSelection() != null) {
 			viewer.setSelection(viewer.getSelection());
 			this.selectionChanged(((IStructuredSelection) viewer.getSelection()).getFirstElement());
-		//	this.currentLabelProvider.setCurrentSelection(currentNode, ((IStructuredSelection) viewer.getSelection()).getFirstElement());
+			//	this.currentLabelProvider.setCurrentSelection(currentNode, ((IStructuredSelection) viewer.getSelection()).getFirstElement());
 		}
-		
+
 	}
 
 	/**
@@ -278,10 +299,10 @@
 		viewer.setInput(bundle);
 		Iterator nodes = viewer.getGraphControl().getNodes().iterator();
 		Graph graph = viewer.getGraphControl();
-		Dimension centre = new Dimension(graph.getBounds().width/2, graph.getBounds().height/2);
-		while ( nodes.hasNext() ) {
+		Dimension centre = new Dimension(graph.getBounds().width / 2, graph.getBounds().height / 2);
+		while (nodes.hasNext()) {
 			GraphNode node = (GraphNode) nodes.next();
-			if ( node.getLocation().x <= 1 && node.getLocation().y <= 1) {
+			if (node.getLocation().x <= 1 && node.getLocation().y <= 1) {
 				node.setLocation(centre.width, centre.height);
 			}
 		}
@@ -292,10 +313,35 @@
 		currentNode = bundle;
 		viewer.setSelection(new StructuredSelection(bundle));
 		this.selectionChanged(bundle);
-		
+
 		// When we load a new model, remove any pinnedNode;
 		this.currentLabelProvider.setPinnedNode(null);
 		this.pinnedNode = null;
+
+		// Check for cycles in the graph
+		Object[] elements = contentProvider.getElements(currentNode);
+
+		boolean loopsFound = false;
+		int counter = 0;
+		for (int i = 0; i < elements.length; i++) {
+			if (elements[i] instanceof BundleDescription) {
+				BundleDescription bundleDescription = (BundleDescription) elements[i];
+				IPluginModelBase model = PluginRegistry.findModel(bundleDescription);
+				DependencyLoop[] loops = DependencyLoopFinder.findLoops(((IPluginModel) model).getPlugin());
+				if (loops.length > 0) {
+					counter += loops.length;
+					loopsFound = true;
+				}
+			} else {
+				// We don't need to worry about looking for cycles in BundleSpecifications (they are not resolved)
+				continue;
+			}
+		}
+		managedForm.getMessageManager().removeAllMessages();
+		if (loopsFound) {
+			managedForm.getMessageManager().addMessage(new Object(), counter + " Cycles Found", new Object(), IMessage.ERROR);
+			//form.sIetMessage(counter + " Cycles found in Graph");
+		}
 	}
 
 	/**
@@ -310,7 +356,7 @@
 				if (dialog.open() == Window.OK) {
 					IPluginModelBase pluginModelBase = (IPluginModelBase) dialog.getFirstResult();
 					focusOn(pluginModelBase.getBundleDescription(), true);
-					
+
 					// When a new plug-in is selected, disable the forward action			
 					// The forward action only stores history when the back button was used (much like a browser)
 					forwardStack.clear();
@@ -340,27 +386,27 @@
 		historyAction.setToolTipText("Previous plugin");
 		historyAction.setEnabled(false);
 		historyAction.setImageDescriptor(Activator.getDefault().getImageRegistry().getDescriptor(Activator.BACKWARD_ENABLED));
-		
+
 		forwardAction = new Action() {
 			public void run() {
-				if ( forwardStack.size() > 0 ) {
+				if (forwardStack.size() > 0) {
 					Object o = forwardStack.pop();
 					focusOn((BundleDescription) o, true);
-					if ( forwardStack.size() <= 0 ) {
+					if (forwardStack.size() <= 0) {
 						forwardAction.setEnabled(false);
 					}
 				}
 			}
 		};
-		
+
 		forwardAction.setText("Forward");
 		forwardAction.setToolTipText("Go forward one plugin");
 		forwardAction.setEnabled(false);
 		forwardAction.setImageDescriptor(Activator.getDefault().getImageRegistry().getDescriptor(Activator.FORWARD_ENABLED));
-		
+
 		screenshotAction = new Action() {
 			public void run() {
-		
+
 				Shell shell = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell();
 				Graph g = (Graph) viewer.getControl();
 				Rectangle bounds = g.getContents().getBounds();
@@ -369,23 +415,23 @@
 				final Image image = new Image(null, size.x, size.y);
 				GC gc = new GC(image);
 				SWTGraphics swtGraphics = new SWTGraphics(gc);
-				
+
 				swtGraphics.translate(-1 * bounds.x + viewLocation.x, -1 * bounds.y + viewLocation.y);
 				g.getViewport().paint(swtGraphics);
-				gc.copyArea(image,0,0);
+				gc.copyArea(image, 0, 0);
 				gc.dispose();
-				
+
 				ImagePreviewPane previewPane = new ImagePreviewPane(shell);
 				previewPane.setText("Image Preview");
 				previewPane.open(image, size);
 			}
 		};
-		
+
 		screenshotAction.setText("Take A Screenshot");
 		screenshotAction.setImageDescriptor(Activator.getDefault().getImageRegistry().getDescriptor(Activator.SNAPSHOT));
 		screenshotAction.setToolTipText("Take screenshot");
 		screenshotAction.setEnabled(true);
-		
+
 	}
 
 	/**
@@ -398,7 +444,7 @@
 		focusAction = new Action() {
 			public void run() {
 				focusOn((BundleDescription) objectToFocusOn, true);
-				
+
 				// When a new plug-in is selected, disable the forward action
 				// The forward action only stores history when the back button was used (much like a browser)
 				forwardStack.clear();
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/SmartPathDependencyAnalysis.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/SmartPathDependencyAnalysis.java
index e5cd56f..3c207b8 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/SmartPathDependencyAnalysis.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/SmartPathDependencyAnalysis.java
@@ -49,7 +49,7 @@
 		// Calculates the smart path.
 		if (this.getSelected() != null) {
 			// Get all the dependencies of the root node
-			BundleDescription[] descriptions = AnalysisUtil.getDependencies(this.rootNode);
+			Object[] descriptions = AnalysisUtil.getDependencies(this.rootNode);
 			for (int i = 0; i < descriptions.length; i++) {
 				// For each dependency of the root node, compute the shortest path
 				// to the selected node.  add each of these to to the list of nodes.
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/VisualizationForm.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/VisualizationForm.java
index 5f89b3b..dc396f9 100644
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/VisualizationForm.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/visualization/dependency/views/VisualizationForm.java
@@ -11,6 +11,7 @@
 package org.eclipse.pde.visualization.dependency.views;
 
 import org.eclipse.mylyn.zest.core.viewers.GraphViewer;
+import org.eclipse.pde.visualization.dependency.Activator;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.SashForm;
 import org.eclipse.swt.events.SelectionAdapter;
@@ -20,9 +21,10 @@
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.forms.ManagedForm;
 import org.eclipse.ui.forms.widgets.ExpandableComposite;
-import org.eclipse.ui.forms.widgets.Form;
 import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
 import org.eclipse.ui.forms.widgets.Section;
 import org.eclipse.ui.forms.widgets.TableWrapData;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
@@ -64,8 +66,9 @@
 	/*
 	 * Some parts of the form we may need access to
 	 */
-	private Form form;
+	private ScrolledForm form;
 	private FormToolkit toolkit;
+	private ManagedForm managedForm;
 	private GraphViewer viewer;
 	private PluginVisualizationView view;
 
@@ -89,12 +92,14 @@
 	VisualizationForm(Composite parent, FormToolkit toolkit, PluginVisualizationView view) {
 		this.toolkit = toolkit;
 		this.view = view;
-		form = this.toolkit.createForm(parent);
+		form = this.toolkit.createScrolledForm(parent);
+		managedForm = new ManagedForm(this.toolkit, this.form);
 		form.getBody().setLayout(new FillLayout());
 		form.setText(Plugin_Dependency_Analysis);
+		form.setImage(Activator.getDefault().getImageRegistry().get(Activator.REQ_PLUGIN_OBJ));
 		createSash(form.getBody());
 	}
-
+	
 	/**
 	 * Creates the sashform to seperate the graph from the controls.
 	 * 
@@ -117,6 +122,7 @@
 	 * @param parent
 	 */
 	private void createGraphSection(Composite parent) {
+		
 		Section section = this.toolkit.createSection(parent, Section.EXPANDED | Section.TITLE_BAR);
 		section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
 		section.setLayout(new FillLayout());
@@ -265,8 +271,12 @@
 	/**
 	 * Gets the form we created.
 	 */
-	public Form getForm() {
+	public ScrolledForm getForm() {
 		return form;
 	}
+	
+	public ManagedForm getManagedForm() {
+		return managedForm;
+	}
 
 }