Bug 75282 - Composite breakpoint groups
diff --git a/org.eclipse.debug.ui/plugin.xml b/org.eclipse.debug.ui/plugin.xml
index a60e9d1..21936f1 100644
--- a/org.eclipse.debug.ui/plugin.xml
+++ b/org.eclipse.debug.ui/plugin.xml
@@ -701,6 +701,14 @@
                label="%clearDefaultGroup.label"
                tooltip="%clearDefaultGroup.tooltip">
          </action>
+         <action
+               id="org.eclipse.debug.ui.breakpointsView.toolbar.showByAction"
+               menubarPath="defaultBreakpointGroup"
+               class="org.eclipse.debug.internal.ui.actions.ShowBreakpointsByAction"
+               helpContextId="show_breakpoints_by_action_context"
+               label="Show By..."
+               tooltip="Choose how to show breakpoints">
+         </action>
       </viewContribution>
 <!-- Contributions to Expression View Toolbar -->
       <viewContribution
@@ -2195,12 +2203,19 @@
           point="org.eclipse.debug.ui.breakpointContainerFactories">
           <breakpointContainerFactory
           	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointProjectContainerFactory"
-          	id="org.eclipse.debug.ui.breakpointProjectContainerFactory"/>
+          	id="org.eclipse.debug.ui.breakpointProjectContainerFactory"
+          	label="Project"/>
           <breakpointContainerFactory
           	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointFileContainerFactory"
-          	id="org.eclipse.debug.ui.breakpointFileContainerFactory"/>
+          	id="org.eclipse.debug.ui.breakpointFileContainerFactory"
+          	label="File"/>
           <breakpointContainerFactory
           	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointTypeContainerFactory"
-          	id="org.eclipse.debug.ui.breakpointTypeContainerFactory"/>
+          	id="org.eclipse.debug.ui.breakpointTypeContainerFactory"
+          	label="Breakpoint Type"/>
+          <breakpointContainerFactory
+          	class="org.eclipse.debug.internal.ui.views.breakpoints.BreakpointGroupContainerFactory"
+          	id="org.eclipse.debug.ui.breakpointGroupContainerFactory"
+          	label="Group"/>
     </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
index ad7eae7..1549a1c 100644
--- a/org.eclipse.debug.ui/schema/breakpointContainerFactories.exsd
+++ b/org.eclipse.debug.ui/schema/breakpointContainerFactories.exsd
@@ -57,6 +57,13 @@
                </appInfo>

             </annotation>

          </attribute>

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

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

       </complexType>

    </element>

 

diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByAction.java
new file mode 100644
index 0000000..d77f3de
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByAction.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.actions;
+
+import java.util.List;
+
+import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsView;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * 
+ */
+public class ShowBreakpointsByAction implements IViewActionDelegate {
+	
+	private BreakpointsView fView;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
+	 */
+	public void init(IViewPart view) {
+		fView= (BreakpointsView) view;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+	 */
+	public void run(IAction action) {
+		ShowBreakpointsByDialog dialog = new ShowBreakpointsByDialog(fView);
+		if (dialog.open() == Dialog.OK) {
+			List selectedContainers = dialog.getSelectedContainers();
+			fView.setBreakpointContainerFactories(selectedContainers);
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+	 */
+	public void selectionChanged(IAction action, ISelection selection) {
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByDialog.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByDialog.java
new file mode 100644
index 0000000..7080347
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ShowBreakpointsByDialog.java
@@ -0,0 +1,382 @@
+/*******************************************************************************
+ * 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.actions;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointContainerFactoryManager;
+import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsView;
+import org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.internal.dialogs.ViewLabelProvider;
+
+/**
+ * 
+ */
+public class ShowBreakpointsByDialog extends Dialog {
+	
+	private BreakpointsView fView;
+	
+	// List viewer that presents available containers
+	private ListViewer fAvailableViewer;
+	private AvailableContainersProvider fAvailableContainersProvider= new AvailableContainersProvider();
+	
+	// Tree viewer that presents selected containers
+	private TreeViewer fSelectedViewer;
+	private SelectedContainerProvider fSelectedContainersProvider= new SelectedContainerProvider();
+	
+	private List fResult= new ArrayList();
+
+	private Button fAddButton;
+	private Button fRemoveButton;
+	private Button fMoveUpButton;
+	private Button fMoveDownButton;
+	
+	private SelectionAdapter fSelectionListener= new SelectionAdapter() {
+		public void widgetSelected(SelectionEvent e) {
+			Object source= e.getSource();
+			if (source == fAddButton) {
+				handleAddPressed();
+			} else if (source == fRemoveButton) {
+				handleRemovePressed();
+			} else if (source == fMoveUpButton) {
+				handleMoveUpPressed();
+			} else if (source == fMoveDownButton) {
+				handleMoveDownPressed();
+			}
+		}
+	};
+
+	/**
+	 * @param parentShell
+	 */
+	protected ShowBreakpointsByDialog(BreakpointsView view) {
+		super(view.getSite().getShell());
+		fView= view;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+	 */
+	protected Control createDialogArea(Composite parent) {
+		ILabelProvider labelProvider= new BreakpointContainerFactoryLabelProvider();
+		
+		Composite parentComposite= (Composite) super.createDialogArea(parent);
+		Composite composite= new Composite(parentComposite, SWT.NONE);
+		GridLayout layout= new GridLayout(2, false);
+		composite.setLayout(layout);
+		GridData data= new GridData(GridData.FILL_BOTH);
+		data.widthHint= 400;
+		data.heightHint= 400;
+		composite.setLayoutData(data);
+		
+		IBreakpointContainerFactory[] factories = BreakpointContainerFactoryManager.getDefault().getFactories();
+		for (int i = 0; i < factories.length; i++) {
+			fAvailableContainersProvider.addAvailable(factories[i]);
+		}
+		List activeFactories = fView.getBreakpointContainerFactories();
+		Iterator iter = activeFactories.iterator();
+		while (iter.hasNext()) {
+			fSelectedContainersProvider.addSelected((IBreakpointContainerFactory) iter.next());
+		}
+		
+		Label label= new Label(composite, SWT.NONE);
+		label.setText("Available Containers:");
+		data= new GridData();
+		data.horizontalSpan= 2;
+		label.setLayoutData(data);
+		
+		fAvailableViewer= new ListViewer(composite);
+		fAvailableViewer.setContentProvider(fAvailableContainersProvider);
+		fAvailableViewer.setLabelProvider(labelProvider);
+		fAvailableViewer.setInput(new Object());
+		fAvailableViewer.getList().setLayoutData(new GridData(GridData.FILL_BOTH));
+		fAvailableViewer.addDoubleClickListener(new IDoubleClickListener() {
+			public void doubleClick(DoubleClickEvent event) {
+				handleAddPressed();
+			}
+		});
+		fAvailableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+			public void selectionChanged(SelectionChangedEvent event) {
+				updateAddButton();
+			}
+		});
+		
+		fAddButton= new Button(composite, SWT.PUSH);
+		fAddButton.setText("Add");
+		fAddButton.addSelectionListener(fSelectionListener);
+		
+		label= new Label(composite, SWT.NONE);
+		label.setText("Displayed Containers:");
+		data= new GridData();
+		data.horizontalSpan= 2;
+		label.setLayoutData(data);
+		
+		fSelectedViewer= new TreeViewer(composite);
+		fSelectedViewer.setContentProvider(fSelectedContainersProvider);
+		fSelectedViewer.setLabelProvider(labelProvider);
+		fSelectedViewer.setInput(new Object());
+		fSelectedViewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
+		fSelectedViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+			public void selectionChanged(SelectionChangedEvent event) {
+				updateSelectedButtons();
+			}
+		});
+		
+		Composite buttonComposite= new Composite(composite, SWT.NONE);
+		buttonComposite.setLayout(new GridLayout());
+		buttonComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+		
+		fRemoveButton= new Button(buttonComposite, SWT.PUSH);
+		fRemoveButton.setText("Remove");
+		fRemoveButton.addSelectionListener(fSelectionListener);
+		
+		fMoveUpButton= new Button(buttonComposite, SWT.PUSH);
+		fMoveUpButton.setText("Move Up");
+		fMoveUpButton.addSelectionListener(fSelectionListener);
+		
+		fMoveDownButton= new Button(buttonComposite, SWT.PUSH);
+		fMoveDownButton.setText("Move Down");
+		fMoveDownButton.addSelectionListener(fSelectionListener);
+		
+		updateViewers();
+		
+		return parentComposite;
+	}
+	
+	public List getSelectedContainers() {
+		return fResult;
+	}
+	
+	protected void okPressed() {
+		Object[] factories= fSelectedContainersProvider.getElements(null);
+		while (factories.length > 0) {
+			Object factory= factories[0];
+			fResult.add(factory);
+			factories= fSelectedContainersProvider.getChildren(factory);
+		}
+		super.okPressed();
+	}
+	
+	public void handleAddPressed() {
+		IStructuredSelection selection= (IStructuredSelection) fAvailableViewer.getSelection();
+		if (selection.size() < 1) {
+			return;
+		}
+		Iterator iter= selection.iterator();
+		while (iter.hasNext()) {
+			fSelectedContainersProvider.addSelected((IBreakpointContainerFactory) iter.next());
+		}
+		updateViewers();
+	}
+	
+	public void handleRemovePressed() {
+		IStructuredSelection selection= (IStructuredSelection) fSelectedViewer.getSelection();
+		if (selection.size() < 1) {
+			return;
+		}
+		Iterator iter= selection.iterator();
+		while (iter.hasNext()) {
+			fAvailableContainersProvider.addAvailable((IBreakpointContainerFactory) iter.next());
+		}
+		updateViewers();
+	}
+	
+	/**
+	 * Moves each selected item up in the tree of selected containers
+	 */
+	public void handleMoveUpPressed() {
+		IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection();
+		Iterator iter = selection.iterator();
+		while (iter.hasNext()) {
+			fSelectedContainersProvider.moveUp(iter.next());
+		}
+		updateViewers();
+	}
+	
+	/**
+	 * Moves each selected item down in the tree of selected containers
+	 */
+	public void handleMoveDownPressed() {
+		IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection();
+		Object[] elements= selection.toArray();
+		for (int i= elements.length - 1; i >= 0; i--) {
+			fSelectedContainersProvider.moveDown(elements[i]);
+		}
+		updateViewers();
+	}
+	
+	public void updateViewers() {
+		fAvailableViewer.refresh();
+		fSelectedViewer.refresh();
+		fSelectedViewer.expandAll();
+		updateAddButton();
+		updateSelectedButtons();
+	}
+	
+	public void updateSelectedButtons() {
+		updateRemoveButton();
+		updateMoveUpButton();
+		updateMoveDownButton();
+	}
+	
+	public void updateAddButton() {
+		fAddButton.setEnabled(fAvailableContainersProvider.getElements(null).length > 0);
+	}
+	
+	public void updateRemoveButton() {
+		fRemoveButton.setEnabled(fSelectedContainersProvider.getElements(null).length > 0);
+	}
+	
+	public void updateMoveUpButton() {
+		boolean enabled= true;
+		IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection();
+		if (selection.size() == 0) {
+			enabled= false;
+		} else {
+			Object firstSelected= selection.getFirstElement();
+			Object parent= fSelectedContainersProvider.getParent(firstSelected);
+			if (!(parent instanceof IBreakpointContainerFactory)) {
+				enabled= false;
+			}
+		}
+		fMoveUpButton.setEnabled(enabled);
+	}
+	
+	public void updateMoveDownButton() {
+		boolean enabled= true;
+		IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection();
+		if (selection.size() == 0) {
+			enabled= false;
+		} else {
+			Object lastSelected= selection.toList().get(selection.size() - 1);
+			Object[] children= fSelectedContainersProvider.getChildren(lastSelected);
+			if (children.length < 1) {
+				enabled= false;
+			}
+		}
+		fMoveDownButton.setEnabled(enabled);
+	}
+	
+	private class AvailableContainersProvider implements IStructuredContentProvider {
+		protected List availableFactories= new ArrayList();
+		
+		public void addAvailable(IBreakpointContainerFactory factory) {
+			availableFactories.add(factory);
+			fSelectedContainersProvider.selectedFactories.remove(factory);
+		}
+		
+		public Object[] getElements(Object inputElement) {
+			return availableFactories.toArray();
+		}
+		
+		public void dispose() {
+		}
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		}
+	}
+	
+	/**
+	 * Content provider that returns the selected breakpoint container factories
+	 * as a tree.
+	 */
+	private class SelectedContainerProvider implements ITreeContentProvider {
+		protected List selectedFactories= new ArrayList();
+		
+		public void addSelected(IBreakpointContainerFactory factory) {
+			selectedFactories.add(factory);
+			fAvailableContainersProvider.availableFactories.remove(factory);
+		}
+		
+		public void moveUp(Object object) {
+			int index = selectedFactories.indexOf(object);
+			if (index > 0) {
+				selectedFactories.remove(object);
+				selectedFactories.add(index - 1, object);
+			}
+		}
+		
+		public void moveDown(Object object) {
+			int index = selectedFactories.indexOf(object);
+			if (index < selectedFactories.size() - 1) {
+				selectedFactories.remove(object);
+				selectedFactories.add(index + 1, object);
+			}
+		}
+
+		public Object[] getChildren(Object parentElement) {
+			// A factory's "child" is the next factory in the list
+			int index = selectedFactories.indexOf(parentElement);
+			if (index < selectedFactories.size() - 1) {
+				return new Object[] { selectedFactories.get(index + 1) };
+			}
+			return new Object[0];
+		}
+
+		public Object getParent(Object element) {
+			// A factory's "parent" is the factory before it
+			int index = selectedFactories.indexOf(element);
+			if (index <= 0 || selectedFactories.size() <= 1) {
+				return null;
+			}
+			return selectedFactories.get(index - 1);
+		}
+
+		public boolean hasChildren(Object element) {
+			// A factory has "children" if there are more
+			// factories after it.
+			int index = selectedFactories.indexOf(element);
+			return index != -1 && index < selectedFactories.size() - 1;
+		}
+
+		public Object[] getElements(Object inputElement) {
+			if (selectedFactories.size() > 0) {
+				return new Object[] { selectedFactories.get(0) };
+			}
+			return new Object[0];
+		}
+		public void dispose() {
+		}
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		}
+	}
+	
+	private class BreakpointContainerFactoryLabelProvider extends ViewLabelProvider {
+		public String getText(Object element) {
+			if (element instanceof IBreakpointContainerFactory) {
+				return ((IBreakpointContainerFactory) element).getLabel();
+			}
+			return null;
+		}
+	}
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/AbstractBreakpointContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/AbstractBreakpointContainerFactory.java
new file mode 100644
index 0000000..0301d52
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/AbstractBreakpointContainerFactory.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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 abstract class AbstractBreakpointContainerFactory implements IBreakpointContainerFactory {
+	
+	protected String fLabel;
+	protected String fIdentifier;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#getContainers(org.eclipse.debug.core.model.IBreakpoint[], java.lang.String)
+	 */
+	public abstract IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId);
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#getLabel()
+	 */
+	public String getLabel() {
+		return fLabel;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#setLabel(java.lang.String)
+	 */
+	public String setLabel(String label) {
+		return fLabel= label;
+	}
+	
+	public void setIdentifier(String id) {
+		fIdentifier= id;
+	}
+	
+	public String getIdentifier() {
+		return fIdentifier;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.internal.ui.views.breakpoints.IBreakpointContainerFactory#dispose()
+	 */
+	public void dispose() {
+	}
+
+}
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
index 3c7fe56..b4acb3c 100644
--- 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
@@ -49,9 +49,11 @@
 		for (int i = 0; i < configurationElements.length; i++) {
 			IConfigurationElement element= configurationElements[i];
 			String id= element.getAttribute("id"); //$NON-NLS-1$
-			if (id != null) {
+			String label= element.getAttribute("label"); //$NON-NLS-1$
+			if (id != null && label != null) {
 				try {
 					IBreakpointContainerFactory factory = (IBreakpointContainerFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
+					factory.setLabel(label);
 					if (factory != null) {
 						fFactories.put(id, factory);
 					}
@@ -70,5 +72,13 @@
 	public IBreakpointContainerFactory getFactory(String identifier) {
 		return (IBreakpointContainerFactory) fFactories.get(identifier);
 	}
+	
+	/**
+	 * Returns the available breakpoint container factories.
+	 * @return the available breakpoint container factories
+	 */
+	public IBreakpointContainerFactory[] getFactories() {
+		return (IBreakpointContainerFactory[]) fFactories.values().toArray(new IBreakpointContainerFactory[0]);
+	}
 
 }
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
index 19d4a18..d87894b 100644
--- 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
@@ -26,7 +26,7 @@
 /**
  * 
  */
-public class BreakpointFileContainerFactory implements IBreakpointContainerFactory {
+public class BreakpointFileContainerFactory extends AbstractBreakpointContainerFactory {
 
 	private ILabelProvider fImageProvider= new WorkbenchLabelProvider();
 	
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointGroupContainerFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointGroupContainerFactory.java
new file mode 100644
index 0000000..a9f1bf0
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointGroupContainerFactory.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+
+/**
+ * 
+ */
+public class BreakpointGroupContainerFactory extends AbstractBreakpointContainerFactory {
+
+	public BreakpointGroupContainerFactory() {
+	}
+
+	/* (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 group= null;
+			try {
+				group = breakpoint.getGroup();
+			} catch (CoreException e) {
+				DebugUIPlugin.log(e);
+			}
+			if (group != null) {
+				List list = (List) map.get(group);
+				if (list == null) {
+					list= new ArrayList();
+					map.put(group, list);
+				}
+				list.add(breakpoint);
+				continue;
+			}
+			// No group
+			other.add(breakpoint);
+		}
+		List containers= new ArrayList(map.size());
+		Set groups = map.keySet();
+		Iterator iter= groups.iterator();
+		while (iter.hasNext()) {
+			String group= (String) iter.next();
+			List list= (List) map.get(group);
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) list.toArray(new IBreakpoint[0]),
+					this,
+					group,
+					parentId);
+			containers.add(container);
+		}
+		if (other.size() > 0) {
+			BreakpointContainer container= new BreakpointContainer(
+					(IBreakpoint[]) other.toArray(new IBreakpoint[0]),
+					this,
+					"(no group)",
+					parentId);
+			containers.add(container);
+		}
+		return (IBreakpointContainer[]) containers.toArray(new IBreakpointContainer[containers.size()]);
+	}
+
+}
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
index 8c1645d..bf7c500 100644
--- 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
@@ -25,7 +25,7 @@
 /**
  * 
  */
-public class BreakpointProjectContainerFactory implements IBreakpointContainerFactory {
+public class BreakpointProjectContainerFactory extends AbstractBreakpointContainerFactory {
 	
 	private ILabelProvider fImageProvider= new WorkbenchLabelProvider();
 	
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
index b001400..c1994fc 100644
--- 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
@@ -22,7 +22,7 @@
 /**
  * 
  */
-public class BreakpointTypeContainerFactory implements IBreakpointContainerFactory {
+public class BreakpointTypeContainerFactory extends AbstractBreakpointContainerFactory {
 	
 	public BreakpointTypeContainerFactory() {
 	}
@@ -62,7 +62,4 @@
 		}
 		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/BreakpointsView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsView.java
index 56351ad..9af58cb 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
@@ -14,6 +14,7 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 import java.util.ListIterator;
 
 import org.eclipse.core.runtime.CoreException;
@@ -74,8 +75,10 @@
 	private boolean fIsTrackingSelection= false;
 	// Persistance constants
 	private static String KEY_IS_TRACKING_SELECTION= "isTrackingSelection"; //$NON-NLS-1$
+	private static String KEY_BREAKPOINT_CONTAINER_FACTORIES= "breakpointContainerFactories"; //$NON-NLS-1$
 	private static String KEY_VALUE="value"; //$NON-NLS-1$
 	private String fAutoGroup= null;
+	private BreakpointsViewContentProvider fContentProvider;
 	
 	/**
 	 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
@@ -94,7 +97,8 @@
 	 */
 	protected Viewer createViewer(Composite parent) {
 		final CheckboxTreeViewer viewer = new CheckboxTreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CHECK));
-		viewer.setContentProvider(new BreakpointsViewContentProvider());
+		fContentProvider= new BreakpointsViewContentProvider();
+		viewer.setContentProvider(fContentProvider);
 		viewer.setLabelProvider(new DelegatingModelPresentation() {
 			public Image getImage(Object item) {
 				if (item instanceof IBreakpointContainer) {
@@ -130,6 +134,7 @@
 		// Necessary so that the PropertySheetView hears about selections in this view
 		getSite().setSelectionProvider(viewer);
 		initIsTrackingSelection();
+		initBreakpointContainerFactories();
 		setEventHandler(new BreakpointsViewEventHandler(this));
 		return viewer;
 	}
@@ -149,6 +154,32 @@
 		}
 		setTrackSelection(false);
 	}
+	
+	private void initBreakpointContainerFactories() {
+		IMemento memento = getMemento();
+		if (memento != null) {
+			IMemento node = memento.getChild(KEY_BREAKPOINT_CONTAINER_FACTORIES);
+			if (node != null) {
+				String factoryIds = node.getString(KEY_VALUE);
+				BreakpointContainerFactoryManager manager = BreakpointContainerFactoryManager.getDefault();
+				List factories= new ArrayList();
+				int start= 0;
+				int index= factoryIds.indexOf(',');
+				while (index != -1 && start < factoryIds.length() - 1) {
+					String factoryId= factoryIds.substring(start, index);
+					if (factoryId.length() > 0) {
+						IBreakpointContainerFactory factory = manager.getFactory(factoryId);
+						if (factory != null) {
+							factories.add(factory);
+						}
+					}
+					start= index + 1;
+					index= factoryIds.indexOf(',', start);
+				}
+				fContentProvider.setBreakpointContainerFactories(factories);
+			}
+		}
+	}
 
 	/**
 	 * Sets the initial checked state of the items in the viewer.
@@ -164,34 +195,47 @@
 		}
 		ListIterator iterator= elementsToCheck.listIterator();
 		while (iterator.hasNext()) {
+			updateCheckedState(iterator.next(), viewer, provider);
+		}
+	}
+	
+	public void updateCheckedState(Object element, CheckboxTreeViewer viewer, ITreeContentProvider provider) {
+		if (element instanceof IBreakpoint) {
 			try {
-				Object element= iterator.next();
-				if (element instanceof IBreakpoint && !((IBreakpoint) element).isEnabled()) {
-					iterator.remove();
-				} else if (element instanceof IBreakpointContainer) {
-					IBreakpoint[] children = ((IBreakpointContainer) element).getBreakpoints();
-					int enabledChildren= 0;
-					for (int i = 0; i < children.length; i++) {
-						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 container node
-						viewer.setGrayed(element, true);
-					} else if (enabledChildren == 0) {
-						// Uncheck the container node if no children are enabled
-						iterator.remove();
-						viewer.setGrayed(element, false);
-					}
-				}
+				viewer.setChecked(element, ((IBreakpoint) element).isEnabled());
 			} catch (CoreException e) {
 				DebugUIPlugin.log(e);
 			}
+		} else if (element instanceof IBreakpointContainer) {
+			IBreakpoint[] breakpoints = ((IBreakpointContainer) element).getBreakpoints();
+			int enabledChildren= 0;
+			for (int i = 0; i < breakpoints.length; i++) {
+				IBreakpoint breakpoint = breakpoints[i];
+				try {
+					if (breakpoint.isEnabled()) {
+						enabledChildren++;
+					}
+				} catch (CoreException e) {
+					DebugUIPlugin.log(e);
+				}
+			}
+			if (enabledChildren == 0) {
+				// Uncheck the container node if no children are enabled
+				viewer.setGrayChecked(element, false);
+			} else if (enabledChildren == breakpoints.length) {
+				// Check the container if all children are enabled
+				viewer.setGrayed(element, false);
+				viewer.setChecked(element, true);
+			} else {
+				// If some but not all children are enabled, gray the container node
+				viewer.setGrayChecked(element, true);
+			}
+			// Update any children (breakpoints and containers)
+			Object[] children = provider.getChildren(element);
+			for (int i = 0; i < children.length; i++) {
+				updateCheckedState(children[i], viewer, provider);
+			}
 		}
-		viewer.setCheckedElements(elementsToCheck.toArray());
 	}
 	
 	/**
@@ -287,7 +331,7 @@
 		ITreeContentProvider contentProvider= getTreeContentProvider();
 		try {
 			breakpoint.setEnabled(enable);
-			updateParentContainers(breakpoint, enable);
+			updateParentsCheckedState(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$
@@ -307,7 +351,7 @@
 	 * @param object
 	 * @param enable
 	 */
-	public void updateParentContainers(Object object, boolean enable) {
+	public void updateParentsCheckedState(Object object, boolean enable) {
 		Object parent= getTreeContentProvider().getParent(object);
 		if (!(parent instanceof IBreakpointContainer)) {
 			return;
@@ -332,7 +376,7 @@
 			} catch (CoreException e) {
 			}
 		}
-		updateParentContainers(parent, enable);
+		updateParentsCheckedState(parent, enable);
 	}
 
 	/**
@@ -521,6 +565,16 @@
 		super.saveState(memento);
 		IMemento node= memento.createChild(KEY_IS_TRACKING_SELECTION);
 		node.putString(KEY_VALUE, String.valueOf(fIsTrackingSelection));
+		
+		StringBuffer buffer= new StringBuffer();
+		List breakpointContainerFactories = getBreakpointContainerFactories();
+		Iterator iter = breakpointContainerFactories.iterator();
+		while (iter.hasNext()) {
+			IBreakpointContainerFactory factory= (IBreakpointContainerFactory) iter.next();
+			buffer.append(factory.getIdentifier()).append(',');
+		}
+		node = memento.createChild(KEY_BREAKPOINT_CONTAINER_FACTORIES);
+		node.putString(KEY_VALUE, buffer.toString());
 	}
 
 	/* (non-Javadoc)
@@ -585,4 +639,16 @@
           }
 		super.doubleClick(event);
 	}
+
+	/**
+	 * @param selectedContainers
+	 */
+	public void setBreakpointContainerFactories(List selectedContainers) {
+		fContentProvider.setBreakpointContainerFactories(selectedContainers);
+		getViewer().refresh();
+	}
+	
+	public List getBreakpointContainerFactories() {
+		return fContentProvider.getBreakpointContainerFactories();
+	}
 }
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 46b529f..ba9f45d 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
@@ -57,6 +57,9 @@
 			} else {
 				IBreakpointContainerFactory nextFactory = (IBreakpointContainerFactory) fBreakpointContainerFactories.get(index + 1);
 				children= nextFactory.getContainers(container.getBreakpoints(), getParentId(container));
+				if (children.length == 1) {
+					children= getElements(children[0]);
+				}
 			}
 		} else {
 			children= new Object[0];
@@ -84,6 +87,10 @@
 		}
 		fBreakpointContainerFactories= factories;
 	}
+	
+	public List getBreakpointContainerFactories() {
+		return fBreakpointContainerFactories;
+	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
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 e02cc80..efd3009 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
@@ -84,26 +84,6 @@
 						}
 						CheckboxTreeViewer viewer = fView.getCheckboxViewer();
 						viewer.refresh();
-						if (autoGroup != null) {
-						    // After updating to pick up structural changes (possible new group creation),
-						    // update the checked state of the default group.
-							int enabledChildren= 0;
-							Object[] children = fView.getTreeContentProvider().getChildren(autoGroup);
-							for (int i = 0; i < children.length; i++) {
-                                try {
-                                    if (((IBreakpoint) children[i]).isEnabled()) {
-                                        enabledChildren++;
-                                    }
-                                } catch (CoreException e) {
-                                }
-                            }
-							if (enabledChildren == children.length) {
-							    viewer.setChecked(autoGroup, true);
-							    viewer.setGrayed(autoGroup, false);
-							} else {
-							    viewer.setGrayChecked(autoGroup, enabledChildren > 0);
-							}
-						}
 						MultiStatus status= new MultiStatus(DebugUIPlugin.getUniqueIdentifier(), IStatus.ERROR, DebugUIViewsMessages.getString("BreakpointsViewEventHandler.4"), null); //$NON-NLS-1$
 						for (int i = 0; i < breakpoints.length; i++) {
 							IBreakpoint breakpoint = breakpoints[i];
@@ -116,6 +96,7 @@
 								if (viewer.getChecked(breakpoint) != enabled) {
 									viewer.setChecked(breakpoint, breakpoint.isEnabled());								
 								}
+								fView.updateParentsCheckedState(breakpoint, enabled);
 
                                 if (!DebugPlugin.getDefault().getBreakpointManager().isEnabled()) {
                                 	fView.updateViewerBackground();
@@ -145,6 +126,7 @@
 					if (fView.isAvailable()) {
 						CheckboxTreeViewer viewer= (CheckboxTreeViewer)fView.getViewer();
 						viewer.refresh();
+						fView.initializeCheckedState();
 						fView.updateObjects();
 					}
 				}
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
index f6b9e47..c31fe48 100644
--- 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
@@ -26,6 +26,12 @@
 	 */
 	public IBreakpointContainer[] getContainers(IBreakpoint[] breakpoints, String parentId);
 	
+	public String getLabel();
+	
+	public String setLabel(String label);
+	
+	public String getIdentifier();
+	
 	/**
 	 * Disposes this container factory. Allows the factory to clean up any
 	 * resources related to images that it may have used for containers