First commit
diff --git a/org.eclipse.debug.ui/plugin.xml b/org.eclipse.debug.ui/plugin.xml
index d72e41b..a60e9d1 100644
--- a/org.eclipse.debug.ui/plugin.xml
+++ b/org.eclipse.debug.ui/plugin.xml
@@ -41,6 +41,7 @@
    <extension-point id="debugModelContextBindings" name="%DebugModelContextBindingsName" schema="schema/debugModelContextBindings.exsd"/>
    <extension-point id="contextViewBindings" name="%ContextViewBindingsName" schema="schema/contextViewBindings.exsd"/>
    <extension-point id="debugViewContentProviders" name="%DebugViewContentProvidersName" schema="schema/debugViewContentProviders.exsd"/>
+   <extension-point id="breakpointContainerFactories" name="Breakpoint Container Factories" schema="schema/breakpointContainerFactories.exsd"/>
 
 <!-- Extensions -->
    <extension
@@ -2190,4 +2191,16 @@
     <extension point="org.eclipse.core.runtime.preferences">
 		<initializer class="org.eclipse.debug.internal.ui.DebugUIPreferenceInitializer"/>
 	</extension>
+    <extension
+          point="org.eclipse.debug.ui.breakpointContainerFactories">
+          <breakpointContainerFactory
+          	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointProjectContainerFactory"
+          	id="org.eclipse.debug.ui.breakpointProjectContainerFactory"/>
+          <breakpointContainerFactory
+          	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointFileContainerFactory"
+          	id="org.eclipse.debug.ui.breakpointFileContainerFactory"/>
+          <breakpointContainerFactory
+          	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointTypeContainerFactory"
+          	id="org.eclipse.debug.ui.breakpointTypeContainerFactory"/>
+    </extension>
 </plugin>
\ No newline at end of file
diff --git a/org.eclipse.debug.ui/schema/breakpointContainerFactories.exsd b/org.eclipse.debug.ui/schema/breakpointContainerFactories.exsd
new file mode 100644
index 0000000..ad7eae7
--- /dev/null
+++ b/org.eclipse.debug.ui/schema/breakpointContainerFactories.exsd
@@ -0,0 +1,108 @@
+<?xml version='1.0' encoding='UTF-8'?>

+<!-- Schema file written by PDE -->

+<schema targetNamespace="org.eclipse.debug.ui">

+<annotation>

+      <appInfo>

+         <meta.schema plugin="org.eclipse.debug.ui" id="breakpointContainerFactories" name="Breakpoint Container Factories"/>

+      </appInfo>

+      <documentation>

+         [Enter description of this extension point.]

+      </documentation>

+   </annotation>

+

+   <element name="extension">

+      <complexType>

+         <sequence>

+         </sequence>

+         <attribute name="point" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="id" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="name" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <element name="breakpointContainerFactory">

+      <complexType>

+         <attribute name="id" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="class" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appInfo>

+                  <meta.attribute kind="java"/>

+               </appInfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="since"/>

+      </appInfo>

+      <documentation>

+         [Enter the first release in which this extension point appears.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="examples"/>

+      </appInfo>

+      <documentation>

+         [Enter extension point usage example here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="apiInfo"/>

+      </appInfo>

+      <documentation>

+         [Enter API information here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="implementation"/>

+      </appInfo>

+      <documentation>

+         [Enter information about supplied implementation of this extension point.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appInfo>

+         <meta.section type="copyright"/>

+      </appInfo>

+      <documentation>

+         

+      </documentation>

+   </annotation>

+

+</schema>

diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowSupportedBreakpointsAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowSupportedBreakpointsAction.java
index 4415450..2bd3ff6 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowSupportedBreakpointsAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowSupportedBreakpointsAction.java
@@ -24,6 +24,7 @@
 import org.eclipse.debug.internal.ui.DebugUIPlugin;
 import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
 import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsView;
+import org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainer;
 import org.eclipse.debug.ui.IDebugUIConstants;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.IStructuredSelection;
@@ -65,11 +66,11 @@
 		 * @see ViewerFilter#select(Viewer, Object, Object)
 		 */
 		public boolean select(Viewer viewer, Object parentElement, Object element) {
-			if (element instanceof String) {
-				// Breakpoint groups are visible if any of their children are visible.
-				Object[] children = fView.getTreeContentProvider().getChildren(element);
-				for (int i = 0; i < children.length; i++) {
-					if (select(viewer, element, children[i])) {
+			if (element instanceof IBreakpointContainer) {
+				// Breakpoint containers are visible if any of their children are visible.
+				IBreakpoint[] breakpoints = ((IBreakpointContainer) element).getBreakpoints();
+				for (int i = 0; i < breakpoints.length; i++) {
+					if (select(viewer, element, breakpoints[i])) {
 						return true;
 					}
 				}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainer.java
new file mode 100644
index 0000000..861d56a
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainer.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * 
+ */
+public class BreakpointContainer implements IBreakpointContainer {
+	
+	private IBreakpoint[] fBreakpoints;
+	private IBreakpointContainerFactory fParentFactory;
+	private Image fImage;
+	private String fName;
+	private String fParentId;
+	
+	private BreakpointContainer() {
+		// Do not call
+	}
+
+	/**
+	 * Creates a new breakpoint container with the given breakpoints. The
+	 * breakpoint container factory which creates this container must pass
+	 * itself in as the parentFactory.
+	 * @param breakpoints
+	 * @param parentFactory
+	 */
+	public BreakpointContainer(IBreakpoint[] breakpoints, IBreakpointContainerFactory parentFactory, String name, String parentId) {
+		fBreakpoints= breakpoints;
+		fParentFactory= parentFactory;
+		fName= name;
+		fParentId= parentId;
+	}
+	
+	public void setImage(Image image) {
+		fImage= image;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainer#getBreakpoints()
+	 */
+	public IBreakpoint[] getBreakpoints() {
+		return fBreakpoints;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainer#getParentFactory()
+	 */
+	public IBreakpointContainerFactory getParentFactory() {
+		return fParentFactory;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainer#getContainerImage()
+	 */
+	public Image getContainerImage() {
+		return fImage;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainer#getName()
+	 */
+	public String getName() {
+		return fName;
+	}
+	
+	public String getParentId() {
+		return fParentId;
+	}
+	
+	public boolean equals(Object object) {
+		if (object instanceof BreakpointContainer) {
+			BreakpointContainer container = ((BreakpointContainer) object);
+			return container.getName().equals(getName()) && container.getParentId().equals(getParentId());
+		}
+		return false;
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainerFactoryManager.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainerFactoryManager.java
new file mode 100644
index 0000000..3c7fe56
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointContainerFactoryManager.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * 
+ */
+public class BreakpointContainerFactoryManager {
+	
+	private static BreakpointContainerFactoryManager fgManager;
+	
+	private Map fFactories= new HashMap();
+
+	public static BreakpointContainerFactoryManager getDefault() {
+		if (fgManager == null) {
+			fgManager= new BreakpointContainerFactoryManager();
+		}
+		return fgManager;
+	}
+	
+	public BreakpointContainerFactoryManager() {
+		loadContainerFactories();
+	}
+
+	/**
+	 * 
+	 */
+	private void loadContainerFactories() {
+		IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(DebugUIPlugin.getUniqueIdentifier(), IDebugUIConstants.EXTENSION_POINT_BREAKPOINT_CONTAINER_FACTORIES);
+		IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements();
+		for (int i = 0; i < configurationElements.length; i++) {
+			IConfigurationElement element= configurationElements[i];
+			String id= element.getAttribute("id"); //$NON-NLS-1$
+			if (id != null) {
+				try {
+					IBreakpointContainerFactory factory = (IBreakpointContainerFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
+					if (factory != null) {
+						fFactories.put(id, factory);
+					}
+				} catch (CoreException e) {
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Returns the factory with the given identifier or <code>null</code>
+	 * if none.
+	 * @param identifier
+	 * @return
+	 */
+	public IBreakpointContainerFactory getFactory(String identifier) {
+		return (IBreakpointContainerFactory) fFactories.get(identifier);
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointFileContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointFileContainerFactory.java
new file mode 100644
index 0000000..19d4a18
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointFileContainerFactory.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+/**
+ * 
+ */
+public class BreakpointFileContainerFactory implements IBreakpointContainerFactory {
+
+	private ILabelProvider fImageProvider= new WorkbenchLabelProvider();
+	
+	public BreakpointFileContainerFactory() {
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#getContainers(org.eclipse.debug.core.model.IBreakpoint[])
+	 */
+	public IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId) {
+		HashMap map= new HashMap();
+		List other= new ArrayList();
+		for (int i = 0; i < breakpoints.length; i++) {
+			IBreakpoint breakpoint = breakpoints[i];
+			IMarker marker = breakpoint.getMarker();
+			if (marker != null) {
+				IResource resource = marker.getResource();
+				if (resource != null) {
+					List list = (List) map.get(resource);
+					if (list == null) {
+						list= new ArrayList();
+						map.put(resource, list);
+					}
+					list.add(breakpoint);
+					continue;
+				}
+			}
+			// No resource available
+			other.add(breakpoint);
+		}
+		List containers= new ArrayList(map.size());
+		Set resources = map.keySet();
+		Iterator breakpointIter= resources.iterator();
+		while (breakpointIter.hasNext()) {
+			IResource resource= (IResource) breakpointIter.next();
+			List breakpointsForFile= (List) map.get(resource);
+			StringBuffer name= new StringBuffer(resource.getName());
+			if (name.length() < 1) {
+				// If the name's length is 0 (e.g. workspace root),
+				// move breakpoints to "Other"
+				Iterator iter = breakpointsForFile.iterator();
+				while (iter.hasNext()) {
+					other.add(iter.next());
+				}
+				continue;
+			}
+			IContainer parent = resource.getParent();
+            if (parent != null) {
+            	String parentPath= parent.getFullPath().toString().substring(1);
+            	if (parentPath.length() > 0) {
+            		name.append(" ["); //$NON-NLS-1$
+            		name.append(parentPath);
+            		name.append(']');
+            	}
+            }
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) breakpointsForFile.toArray(new IBreakpoint[0]),
+					this,
+					name.toString(),
+					parentId);
+			container.setImage(fImageProvider.getImage(resource));
+			containers.add(container);
+		}
+		if (other.size() > 0) {
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) other.toArray(new IBreakpoint[0]),
+					this,
+					"(no file)",
+					parentId);
+			containers.add(container);
+		}
+		return (IBreakpointContainer[]) containers.toArray(new IBreakpointContainer[containers.size()]);
+	}
+	
+	public void dispose() {
+		fImageProvider.dispose();
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointProjectContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointProjectContainerFactory.java
new file mode 100644
index 0000000..8c1645d
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointProjectContainerFactory.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+/**
+ * 
+ */
+public class BreakpointProjectContainerFactory implements IBreakpointContainerFactory {
+	
+	private ILabelProvider fImageProvider= new WorkbenchLabelProvider();
+	
+	public BreakpointProjectContainerFactory() {
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#getContainers(org.eclipse.debug.core.model.IBreakpoint[])
+	 */
+	public IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId) {
+		HashMap map= new HashMap();
+		List other= new ArrayList();
+		for (int i = 0; i < breakpoints.length; i++) {
+			IBreakpoint breakpoint = breakpoints[i];
+			IMarker marker = breakpoint.getMarker();
+			if (marker != null) {
+				IProject project = marker.getResource().getProject();
+				if (project != null) {
+					List list = (List) map.get(project);
+					if (list == null) {
+						list= new ArrayList();
+						map.put(project, list);
+					}
+					list.add(breakpoint);
+					continue;
+				}
+			}
+			// No project available
+			other.add(breakpoint);
+		}
+		List containers= new ArrayList(map.size());
+		Set projects = map.keySet();
+		Iterator iter= projects.iterator();
+		while (iter.hasNext()) {
+			IProject project= (IProject) iter.next();
+			List list= (List) map.get(project);
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) list.toArray(new IBreakpoint[0]),
+					this,
+					project.getName(),
+					parentId);
+			container.setImage(fImageProvider.getImage(project));
+			containers.add(container);
+		}
+		if (other.size() > 0) {
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) other.toArray(new IBreakpoint[0]),
+					this,
+					"(no project)",
+					parentId);
+			containers.add(container);
+		}
+		return (IBreakpointContainer[]) containers.toArray(new IBreakpointContainer[containers.size()]);
+	}
+	
+	public void dispose() {
+		fImageProvider.dispose();
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointTypeContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointTypeContainerFactory.java
new file mode 100644
index 0000000..b001400
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointTypeContainerFactory.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+/**
+ * 
+ */
+public class BreakpointTypeContainerFactory implements IBreakpointContainerFactory {
+	
+	public BreakpointTypeContainerFactory() {
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#getContainers(org.eclipse.debug.core.model.IBreakpoint[])
+	 */
+	public IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId) {
+		HashMap map= new HashMap();
+		List other= new ArrayList();
+		for (int i = 0; i < breakpoints.length; i++) {
+			IBreakpoint breakpoint = breakpoints[i];
+			String typeName= DebugPlugin.getDefault().getBreakpointManager().getTypeName(breakpoint);
+			if (typeName == null) {
+				typeName= "(other)";
+			}
+			List list = (List) map.get(typeName);
+			if (list == null) {
+				list= new ArrayList();
+				map.put(typeName, list);
+			}
+			list.add(breakpoint);
+			continue;
+		}
+		List containers= new ArrayList(map.size());
+		Set typeNames = map.keySet();
+		Iterator breakpointIter= typeNames.iterator();
+		while (breakpointIter.hasNext()) {
+			String typeName= (String) breakpointIter.next();
+			List list= (List) map.get(typeName);
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) list.toArray(new IBreakpoint[0]),
+					this,
+					typeName,
+					parentId);
+			containers.add(container);
+		}
+		return (IBreakpointContainer[]) containers.toArray(new IBreakpointContainer[containers.size()]);
+	}
+	
+	public void dispose() {
+	}
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsSorter.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsSorter.java
index 79e4311..14f6e7a 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsSorter.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsSorter.java
@@ -49,13 +49,13 @@
 		 *  element is greater than the second element
 		 */
 		public int compare(Viewer viewer, Object e1, Object e2) {
-			// Show sorted groups, then sorted breakpoints.
-			if (e1 instanceof String) {
-				if (e2 instanceof String) {
-					return ((String) e1).compareTo((String) e2);
+			// Show sorted containers, then sorted breakpoints.
+			if (e1 instanceof IBreakpointContainer) {
+				if (e2 instanceof IBreakpointContainer) {
+					return ((IBreakpointContainer) e1).getName().compareTo(((IBreakpointContainer) e2).getName());
 				}
 				return -1;
-			} else if (e2 instanceof String) {
+			} else if (e2 instanceof IBreakpointContainer) {
 				return 1;
 			}
 	
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
index 8f10d89..56351ad 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
@@ -97,11 +97,24 @@
 		viewer.setContentProvider(new BreakpointsViewContentProvider());
 		viewer.setLabelProvider(new DelegatingModelPresentation() {
 			public Image getImage(Object item) {
-				if (item instanceof String) {
-					return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_GROUP);
+				if (item instanceof IBreakpointContainer) {
+					IBreakpointContainer container= (IBreakpointContainer) item;
+					Image image = container.getContainerImage();
+					if (image == null) {
+						image= DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_GROUP);
+					}
+					return image;
 				}
 				return super.getImage(item);
 			}
+			
+			public String getText(Object item) {
+				if (item instanceof IBreakpointContainer) {
+					IBreakpointContainer container= (IBreakpointContainer) item;
+					return container.getName();
+				}
+				return super.getText(item);
+			}
 		});
 		viewer.setSorter(new BreakpointsSorter());
 		viewer.setInput(DebugPlugin.getDefault().getBreakpointManager());
@@ -145,31 +158,31 @@
 		CheckboxTreeViewer viewer= getCheckboxViewer();
 		ITreeContentProvider provider= getTreeContentProvider();
 		Object[] elements= provider.getElements(manager);
-		ArrayList breakpoints= new ArrayList(elements.length);
+		ArrayList elementsToCheck= new ArrayList(elements.length);
 		for (int i = 0; i < elements.length; i++) {
-			breakpoints.add(elements[i]);
+			elementsToCheck.add(elements[i]);
 		}
-		ListIterator iterator= breakpoints.listIterator();
+		ListIterator iterator= elementsToCheck.listIterator();
 		while (iterator.hasNext()) {
 			try {
 				Object element= iterator.next();
 				if (element instanceof IBreakpoint && !((IBreakpoint) element).isEnabled()) {
 					iterator.remove();
-				} else if (element instanceof String) {
-					Object[] children = provider.getChildren(element);
+				} else if (element instanceof IBreakpointContainer) {
+					IBreakpoint[] children = ((IBreakpointContainer) element).getBreakpoints();
 					int enabledChildren= 0;
 					for (int i = 0; i < children.length; i++) {
-						IBreakpoint child = (IBreakpoint) children[i];
-						if (child.isEnabled()) {
-							iterator.add(child);
+						IBreakpoint breakpoint = children[i];
+						if (breakpoint.isEnabled()) {
+							iterator.add(breakpoint);
 							enabledChildren++;
 						}
 					}
 					if (enabledChildren != children.length && enabledChildren > 0) {
-						// If some but not all children are enabled, gray the group node
+						// If some but not all children are enabled, gray the container node
 						viewer.setGrayed(element, true);
 					} else if (enabledChildren == 0) {
-						// Uncheck the group node if no children are enabled
+						// Uncheck the container node if no children are enabled
 						iterator.remove();
 						viewer.setGrayed(element, false);
 					}
@@ -178,7 +191,7 @@
 				DebugUIPlugin.log(e);
 			}
 		}
-		viewer.setCheckedElements(breakpoints.toArray());
+		viewer.setCheckedElements(elementsToCheck.toArray());
 	}
 	
 	/**
@@ -258,8 +271,8 @@
 	 */
 	private void handleCheckStateChanged(CheckStateChangedEvent event) {
 		Object source= event.getElement();
-		if (source instanceof String) {
-			handleGroupChecked(event, (String) source);
+		if (source instanceof IBreakpointContainer) {
+			handleContainerChecked(event, (IBreakpointContainer) source);
 		} else if (source instanceof IBreakpoint) {
 			handleBreakpointChecked(event, (IBreakpoint) source);
 		}
@@ -274,24 +287,7 @@
 		ITreeContentProvider contentProvider= getTreeContentProvider();
 		try {
 			breakpoint.setEnabled(enable);
-			String group = (String) contentProvider.getParent(breakpoint);
-			if (group != null) {
-				// First, assume that all other breakpoints will match the group
-				// (set ungrayed with appropriate check state)
-				if (DebugPlugin.getDefault().getBreakpointManager().isEnabled()) {
-					viewer.setGrayed(group, false);
-				}
-				viewer.setChecked(group, enable);
-				Object[] children = contentProvider.getChildren(group);
-				for (int i = 0; i < children.length; i++) {
-					if (((IBreakpoint) children[i]).isEnabled() != enable) {
-						// Then, if any other breakpoints don't match the
-						// selected breakpoint, gray and check the group.
-						viewer.setGrayChecked(group, true);
-						break;
-					}
-				}
-			}
+			updateParentContainers(breakpoint, enable);
 			viewer.update(breakpoint, null);
 		} catch (CoreException e) {
 			String titleState= enable ? DebugUIViewsMessages.getString("BreakpointsView.6") : DebugUIViewsMessages.getString("BreakpointsView.7"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -303,20 +299,55 @@
 			getCheckboxViewer().addCheckStateListener(fCheckListener);
 		}
 	}
+	
+	/**
+	 * Updates the checked state of the given object's container
+	 * assuming that the child element has changed to the given
+	 * enabled state.
+	 * @param object
+	 * @param enable
+	 */
+	public void updateParentContainers(Object object, boolean enable) {
+		Object parent= getTreeContentProvider().getParent(object);
+		if (!(parent instanceof IBreakpointContainer)) {
+			return;
+		}
+		CheckboxTreeViewer viewer= getCheckboxViewer();
+		IBreakpointContainer container= (IBreakpointContainer) parent;
+		// First, assume that all other breakpoints will match the group
+		// (set ungrayed with appropriate check state)
+		if (DebugPlugin.getDefault().getBreakpointManager().isEnabled()) {
+			viewer.setGrayed(container, false);
+		}
+		viewer.setChecked(container, enable);
+		IBreakpoint[] breakpoints = container.getBreakpoints();
+		for (int i = 0; i < breakpoints.length; i++) {
+			try {
+				if (breakpoints[i].isEnabled() != enable) {
+					// Then, if any other breakpoints don't match the
+					// selected breakpoint, gray and check the group.
+					viewer.setGrayChecked(container, true);
+					break;
+				}
+			} catch (CoreException e) {
+			}
+		}
+		updateParentContainers(parent, enable);
+	}
 
 	/**
 	 * A group has been checked or unchecked. Enable/disable all of the
 	 * breakpoints in that group to match.
 	 */
-	private void handleGroupChecked(CheckStateChangedEvent event, String group) {
+	private void handleContainerChecked(CheckStateChangedEvent event, IBreakpointContainer container) {
 		CheckboxTreeViewer viewer= getCheckboxViewer();
-		Object[] children = getTreeContentProvider().getChildren(group);
+		IBreakpoint[] breakpoints = container.getBreakpoints();
 		boolean enable= event.getChecked();
-		viewer.setGrayed(group, false);
+		viewer.setGrayed(container, false);
 		
 		DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(getEventHandler());
-		for (int i = 0; i < children.length; i++) {
-			IBreakpoint breakpoint= (IBreakpoint) children[i];
+		for (int i = 0; i < breakpoints.length; i++) {
+			IBreakpoint breakpoint= breakpoints[i];
 			try {
 				viewer.setChecked(breakpoint, enable);
 				breakpoint.setEnabled(enable);
@@ -326,7 +357,7 @@
 			}
 		}
 		if (!DebugPlugin.getDefault().getBreakpointManager().isEnabled()) {
-			viewer.setGrayed(group, true);
+			viewer.setGrayed(container, true);
 		}
 		DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(getEventHandler());
 		return;
@@ -547,7 +578,7 @@
 		  IStructuredSelection selection= (IStructuredSelection) event.getSelection();
           if (selection.size() == 1) {
               Object element = selection.getFirstElement();
-              if (element instanceof String) {
+              if (element instanceof IBreakpointContainer) {
                   getCheckboxViewer().setExpandedState(element, !getCheckboxViewer().getExpandedState(element));
                   return;
               }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewContentProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewContentProvider.java
index 5143f1d..46b529f 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewContentProvider.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewContentProvider.java
@@ -12,10 +12,11 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.IBreakpointManager;
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.jface.viewers.ITreeContentProvider;
@@ -23,33 +24,65 @@
 
 public class BreakpointsViewContentProvider implements ITreeContentProvider {
 	
-	private Map elements= new HashMap();
+	private List fBreakpointContainerFactories= new ArrayList();
+	
+	private Map fParentMap= new HashMap();
+	
+	public BreakpointsViewContentProvider() {
+		fBreakpointContainerFactories.add(BreakpointContainerFactoryManager.getDefault().getFactory("org.eclipse.debug.ui.breakpointTypeContainerFactory"));
+		fBreakpointContainerFactories.add(BreakpointContainerFactoryManager.getDefault().getFactory("org.eclipse.debug.ui.breakpointProjectContainerFactory"));
+		fBreakpointContainerFactories.add(BreakpointContainerFactoryManager.getDefault().getFactory("org.eclipse.debug.ui.breakpointFileContainerFactory"));
+	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
 	 */
 	public Object[] getElements(Object parent) {
-		elements.clear();
-		IBreakpoint[] breakpoints = ((IBreakpointManager) parent).getBreakpoints();
-		for (int i = 0; i < breakpoints.length; i++) {
-			IBreakpoint breakpoint = breakpoints[i];
-			String group= null;
-			try {
-				group = breakpoint.getGroup();
-			} catch (CoreException e) {
-			}
-			if (group != null) {
-				List list= (List) elements.get(group);
-				if (list == null) {
-					list= new ArrayList();
-					elements.put(group, list);
-				}
-				list.add(breakpoint);
+		Object children[];
+		IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+		if (fBreakpointContainerFactories.isEmpty()) {
+			children= breakpoints;
+		} else if (parent instanceof IBreakpointManager) {
+			IBreakpointContainerFactory factory = (IBreakpointContainerFactory) fBreakpointContainerFactories.get(0);
+			children= factory.getContainers(breakpoints, "");
+		} else if (parent instanceof IBreakpointContainer) {
+			IBreakpointContainer container = ((IBreakpointContainer) parent);
+			IBreakpointContainerFactory parentFactory = container.getParentFactory();
+			int index = fBreakpointContainerFactories.indexOf(parentFactory);
+			if (index == -1) {
+				children= new Object[0];
+			} else if (index == fBreakpointContainerFactories.size() - 1) {
+				// last container level
+				children= container.getBreakpoints();
 			} else {
-				elements.put(breakpoint, null);
+				IBreakpointContainerFactory nextFactory = (IBreakpointContainerFactory) fBreakpointContainerFactories.get(index + 1);
+				children= nextFactory.getContainers(container.getBreakpoints(), getParentId(container));
 			}
+		} else {
+			children= new Object[0];
 		}
-		return elements.keySet().toArray();
+		for (int i = 0; i < children.length; i++) {
+			fParentMap.put(children[i], parent);
+		}
+		return children;
+	}
+	
+	public String getParentId(IBreakpointContainer container) {
+		Object parent= getParent(container);
+		if (parent instanceof IBreakpointContainer) {
+			return getParentId((IBreakpointContainer) parent) + '.' + container.getName();
+		} else if (parent instanceof IBreakpointManager) {
+			return container.getName();
+		}
+		return "";
+	}
+	
+	public void setBreakpointContainerFactories(List factories) {
+		Iterator iter = fBreakpointContainerFactories.iterator();
+		while (iter.hasNext()) {
+			((IBreakpointContainerFactory) iter.next()).dispose();
+		}
+		fBreakpointContainerFactories= factories;
 	}
 
 	/* (non-Javadoc)
@@ -62,39 +95,27 @@
 	 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
 	 */
 	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		elements.clear();
+		fParentMap.clear();
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
 	 */
 	public Object[] getChildren(Object parentElement) {
-		if (parentElement instanceof String) {
-			List list= (List) elements.get(parentElement);
-			if (list != null) {
-				return list.toArray();
-			}
-		}
-		return null;
+		return getElements(parentElement);
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
 	 */
 	public Object getParent(Object element) {
-		if (element instanceof IBreakpoint) {
-			try {
-				return ((IBreakpoint) element).getGroup();
-			} catch (CoreException e) {
-			}
-		}
-		return null;
+		return fParentMap.get(element);
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
 	 */
 	public boolean hasChildren(Object element) {
-		return element instanceof String;
+		return element instanceof IBreakpointContainer;
 	}
 }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewEventHandler.java
index 8961436..e02cc80 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewEventHandler.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsViewEventHandler.java
@@ -13,10 +13,8 @@
 
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IMarkerDelta;
@@ -163,8 +161,8 @@
 				public void run() {
 					if (fView.isAvailable()) {
 						CheckboxTreeViewer viewer = (CheckboxTreeViewer)fView.getViewer();
-						Set changedGroups= getGroupsWithAdditions(breakpoints, deltas);
-						if (changedGroups.size() > 0) {
+						List groupChanged= getGroupChangeBreakpoints(breakpoints, deltas);
+						if (groupChanged.size() > 0) {
 							// If the groups has changed, completely refresh the view to
 							// pick up structural changes.
 							fView.getViewer().refresh();
@@ -174,7 +172,7 @@
 							fView.updateObjects();
 							// Fire a selection change to update contributed actions
 							viewer.setSelection(viewer.getSelection());
-							Iterator iter= changedGroups.iterator();
+							Iterator iter= groupChanged.iterator();
 							while (iter.hasNext()) {
 								viewer.expandToLevel(iter.next(), AbstractTreeViewer.ALL_LEVELS);
 							}
@@ -215,8 +213,14 @@
 		}
 	}
 	
-	private Set getGroupsWithAdditions(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
-		Set changedGroups= new HashSet();
+	/**
+	 * Returns a list of breakpoints (from the given list) that have changed groups.
+	 * @param breakpoints
+	 * @param deltas
+	 * @return
+	 */
+	private List getGroupChangeBreakpoints(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
+		List groupChanged= new ArrayList();
 	    for (int i = 0; i < breakpoints.length; i++) {
 			IBreakpoint breakpoint = breakpoints[i];
 			IMarker marker= breakpoint.getMarker();
@@ -233,13 +237,13 @@
 						if (newGroup == null || oldGroup == null || !newGroup.equals(oldGroup)) {
 							// one is null, one isn't => changed
 						    // both not null && !one.equals(other) => changed
-							changedGroups.add(newGroup);
+							groupChanged.add(breakpoint);
 						}
 					}
 				}
 			}
 		}
-	    return changedGroups;
+	    return groupChanged;
 	}
 
 	/**
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainer.java
new file mode 100644
index 0000000..8b9d557
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainer.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * 
+ */
+public interface IBreakpointContainer {
+	
+	public IBreakpoint[] getBreakpoints();
+	
+	public IBreakpointContainerFactory getParentFactory();
+	
+	/**
+	 * Returns an image to use for this container of <code>null</code>
+	 * if none
+	 * 
+	 * @return an image to use with this container or <code>null</code>
+	 *  if none
+	 */
+	public Image getContainerImage();
+	
+	public String getName();
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainerFactory.java
new file mode 100644
index 0000000..f6b9e47
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/IBreakpointContainerFactory.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.views.breakpoints;
+
+import org.eclipse.debug.core.model.IBreakpoint;
+
+/**
+ * 
+ */
+public interface IBreakpointContainerFactory {
+	
+	/**
+	 * Returns containers for the given set of breakpoints. Each of the
+	 * given breakpoints will appear in exactly one of the returned containers.
+	 * 
+	 * @param breakpoints the breakpoints to put into containers
+	 * @return containers for the given set of breakpoints
+	 */
+	public IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId);
+	
+	/**
+	 * Disposes this container factory. Allows the factory to clean up any
+	 * resources related to images that it may have used for containers 
+	 * it created.
+	 */
+	public void dispose();
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java
index a8dc2be..adf2d52 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/IDebugUIConstants.java
@@ -935,6 +935,8 @@
 	 * components extension point specifies an <code>IVariableComponent</code>
 	 * for an <code>IContextLaunchVariable</code>.
 	 */
-	public static final String EXTENSION_POINT_LAUNCH_VARIABLE_COMPONENTS = "launchVariableComponents";		//$NON-NLS-1$	
+	public static final String EXTENSION_POINT_LAUNCH_VARIABLE_COMPONENTS = "launchVariableComponents";		//$NON-NLS-1$
+	
+	public static final String EXTENSION_POINT_BREAKPOINT_CONTAINER_FACTORIES = "breakpointContainerFactories"; //$NON-NLS-1$
 		
 }