Bug 370805 - Add filtering options in graph visualization
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/GraphContentProvider.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/GraphContentProvider.java
index 462f825..c1e3ba7 100755
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/GraphContentProvider.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/GraphContentProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright 2005, 2009 CHISEL Group, University of Victoria, Victoria, BC,
+ * Copyright 2005, 2012 CHISEL Group, University of Victoria, Victoria, BC,
  * Canada. 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
@@ -10,6 +10,10 @@
  ******************************************************************************/
 package org.eclipse.pde.internal.visualization.dependency.views;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.osgi.service.resolver.BundleDescription;
 import org.eclipse.zest.core.viewers.IGraphEntityContentProvider;
@@ -18,28 +22,109 @@
 
 	Object currentBundle = null;
 	private boolean reverseBundleDependencies;
-
+	private String[] symbolicNamesPatternsToMatch = new String[0];
+	private String[] symbolicNamesPatternsToExclude = new String[0];
+	private boolean hideFragments = false;
 
 	private Object[] getDependencies(Object bundle) {
 		if (bundle != null) {
 			if (reverseBundleDependencies) {
-				return DependencyUtil.getDependentBundles(bundle);
+				return filterBundles(DependencyUtil.getDependentBundles(bundle));
 			}
-			return AnalysisUtil.getPrerequisites(new Object[] { currentBundle });
+			return filterBundles(AnalysisUtil.getPrerequisites(new Object[] { currentBundle }));
 		}
 		return new BundleDescription[0];
 	}
 
 	// Returns all entities that should be linked with the given entity
 	public Object[] getConnectedTo(Object entity) {
+		Object[] bundles = null;
 		if (reverseBundleDependencies) {
-			return DependencyUtil.getConnectedBundles(entity, currentBundle);
+			bundles = DependencyUtil.getConnectedBundles(entity, currentBundle);
+		} else {
+			bundles = AnalysisUtil.getDependencies(entity);
 		}
-		return AnalysisUtil.getDependencies(entity);
+		return filterBundles(bundles);
+	}
+
+	private Object[] filterBundles(Object[] bundles) {
+		if (symbolicNamesPatternsToExclude.length == 0 && symbolicNamesPatternsToMatch.length == 0 && !hideFragments) {
+			return bundles;
+		}
+		List filteredList = new ArrayList();
+		for (int i = 0; i < bundles.length; i++) {
+			Object object = bundles[i];
+			if (object instanceof BundleDescription) {
+				BundleDescription bundleDesc = (BundleDescription) object;
+				if (keepBundle(bundleDesc)) {
+					filteredList.add(object);
+				}
+			} else {
+				// What type of object is it ??? Keep it in the list as long as we don't want to filter things we don't understand
+				filteredList.add(object);
+			}
+		}
+		return filteredList.toArray();
+	}
+
+	/**
+	 * Keep bundle if at least one of symbolic names to match pattern is matched and if none of symbolicNamePatternsToExclude is matched 
+	 * @param bundleDesc
+	 * @return
+	 */
+	private boolean keepBundle(BundleDescription bundleDesc) {
+		if (hideFragments && bundleDesc.getHost() != null) {
+			// Hide fragments
+			return false;
+		}
+		String symbolicName = bundleDesc.getSymbolicName();		
+		if (symbolicNamesPatternsToMatch.length > 0) {
+			boolean keepBundle = false;
+			for (int i = 0; i < symbolicNamesPatternsToMatch.length; i++) {
+				String patternToMatch = symbolicNamesPatternsToMatch[i];
+				if (Pattern.matches(patternToMatch, symbolicName)) {
+					keepBundle = true;
+					break;
+				}
+			}
+			if (!keepBundle) {
+				// Non of symbolicNamesPatternsToMatch is matched
+				return false;
+			}
+		}		
+		for (int i = 0; i < symbolicNamesPatternsToExclude.length; i++) {
+			String patternToExclude = symbolicNamesPatternsToExclude[i];
+			if (Pattern.matches(patternToExclude, symbolicName)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Should match at least one of the patterns
+	 * @param patternsToMatch
+	 */
+	public void setSymbolicNamesPatternsToMatch(String[] patternsToMatch) {
+		if (patternsToMatch == null) {
+			throw new IllegalArgumentException("patternsToMatch should not be null");
+		}
+		symbolicNamesPatternsToMatch = patternsToMatch;
+	}
+
+	public void setSymbolicNamesPatternsToExcludes(String[] patternsToExclude) {
+		if (patternsToExclude == null) {
+			throw new IllegalArgumentException("patternsToExclude should not be null");
+		}
+		symbolicNamesPatternsToExclude = patternsToExclude;
+	}
+
+	public void setHideFragments(boolean pHideFragments) {
+		hideFragments = pHideFragments;
 	}
 
 	public Object[] getElements(Object inputElement) {
-		return getDependencies(inputElement);
+		return filterBundles(getDependencies(inputElement));
 
 	}
 
@@ -54,7 +139,6 @@
 
 	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
 		currentBundle = newInput;
-
 	}
 
 	public void setReverseBundleDependencies(boolean enable) {
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/PluginVisualizationView.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/PluginVisualizationView.java
index dc694b3..a983a4b 100755
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/PluginVisualizationView.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/PluginVisualizationView.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright 2005, 2000 CHISEL Group, University of Victoria, Victoria, BC,
+ * Copyright 2005, 2012 CHISEL Group, University of Victoria, Victoria, BC,
  * Canada. 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
@@ -704,4 +704,32 @@
 		return viewer;
 	}
 
+	void setSymbolicNameMatchPattern(String pPattern) {
+		if (pPattern.trim().length() >0) {
+			this.contentProvider.setSymbolicNamesPatternsToMatch(new String[]{pPattern.trim()});
+		} else {
+			this.contentProvider.setSymbolicNamesPatternsToMatch(new String[0]);
+		}
+		
+		viewer.refresh();
+		viewer.applyLayout();
+	}
+
+	void setSymbolicNameExcludePattern(String pPattern) {
+		if (pPattern.trim().length() >0) {
+			this.contentProvider.setSymbolicNamesPatternsToExcludes(new String[]{pPattern.trim()});
+		} else {
+			this.contentProvider.setSymbolicNamesPatternsToExcludes(new String[0]);
+		}
+		
+		viewer.refresh();
+		viewer.applyLayout();
+	}
+
+	public void setHideFragments(boolean pHideFragments) {		
+		this.contentProvider.setHideFragments(pHideFragments);		
+		viewer.refresh();
+		viewer.applyLayout();
+	}
+
 }
\ No newline at end of file
diff --git a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/VisualizationForm.java b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/VisualizationForm.java
index 349be18..319918f 100755
--- a/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/VisualizationForm.java
+++ b/visualization/plugins/org.eclipse.pde.visualization.dependency/src/org/eclipse/pde/internal/visualization/dependency/views/VisualizationForm.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright 2005, 2009 CHISEL Group, University of Victoria, Victoria, BC,
+ * Copyright 2005, 2012 CHISEL Group, University of Victoria, Victoria, BC,
  * Canada. 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
@@ -60,6 +60,9 @@
  */
 /* package */class VisualizationForm {
 
+	private static final String SymbolicName_Match_Pattern = "Bundle Name Match Regexp";
+	private static final String SymbolicName_Exclude_Pattern = "Bundle Name Exclude Regexp";
+	private static final String Hide_Fragments = "Hide Fragments";
 	/*
 	 * These are all the strings used in the form. These can probably be
 	 * abstracted for internationalization
@@ -410,6 +413,38 @@
 
 		setDependencyPath(false);
 		dependencyOptions.setClient(dependencyOptionsComposite);
+		
+		
+		Composite filteringComposite = this.toolkit.createComposite(controlComposite, SWT.NONE);
+		filteringComposite.setLayout(new GridLayout(1, false));
+		final Button hideFragmentsButton = this.toolkit.createButton(filteringComposite, Hide_Fragments, SWT.CHECK);
+		hideFragmentsButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				view.setHideFragments(hideFragmentsButton.getSelection());				
+			}
+		});
+		
+		this.toolkit.createLabel(filteringComposite, SymbolicName_Match_Pattern);
+		final Text symbolicNamesMatchPattern = this.toolkit.createText(filteringComposite, "", SWT.BORDER);
+		symbolicNamesMatchPattern.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
+		symbolicNamesMatchPattern.addModifyListener(new ModifyListener() {
+			
+			public void modifyText(ModifyEvent arg0) {
+				view.setSymbolicNameMatchPattern(symbolicNamesMatchPattern.getText());
+			}
+		});
+		
+		this.toolkit.createLabel(filteringComposite, SymbolicName_Exclude_Pattern);
+		final Text symbolicNamesExcludePattern = this.toolkit.createText(filteringComposite, "", SWT.BORDER);
+		symbolicNamesExcludePattern.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
+		symbolicNamesExcludePattern.addModifyListener(new ModifyListener() {
+			
+			public void modifyText(ModifyEvent arg0) {
+				view.setSymbolicNameExcludePattern(symbolicNamesExcludePattern.getText());
+			}
+		});
+		
+		
 
 		controls.setClient(controlComposite);
 	}