Bug 44986 - Support for Breakpoint groups
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/Breakpoint.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/Breakpoint.java
index f3e5684..dae4502 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/Breakpoint.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/Breakpoint.java
@@ -144,6 +144,20 @@
 	}
 	
 	/**
+	 * @see IBreakpoint#getGroup()
+	 */
+	public String getGroup() throws CoreException {
+		return getMarker().getAttribute(GROUP, null);
+	}
+	
+	/**
+	 * @see IBreakpoint#setGroup(String)
+	 */
+	public void setGroup(String group) throws CoreException {
+		setAttribute(GROUP, group);
+	}
+	
+	/**
 	 * Convenience method to set the given boolean attribute of
 	 * this breakpoint's underlying marker in a workspace
 	 * runnable. Setting marker attributes in a workspace runnable
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IBreakpoint.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IBreakpoint.java
index 3c0b188..dd4a09d 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IBreakpoint.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/IBreakpoint.java
@@ -114,7 +114,14 @@
 	 *
 	 * @see org.eclipse.core.resources.IMarker#getAttribute(String, boolean)
 	 */
-	public static final String PERSISTED= "org.eclipse.debug.core.persisted"; //$NON-NLS-1$		
+	public static final String PERSISTED= "org.eclipse.debug.core.persisted"; //$NON-NLS-1$
+	
+	/**
+	 * Breakpoint group marker attribute (value <code>"org.eclipse.debug.core.group"</code>).
+	 * The attribute is a <code>String</code> corresponding to the group
+	 * name.
+	 */
+	public static final String GROUP= "org.eclipse.debug.core.group"; //$NON-NLS-1$
 	
 	/**
 	 * Deletes this breakpoint's underlying marker, and removes
@@ -215,7 +222,28 @@
 	 * @exception CoreException if unable to set the associated attribute on
 	 *  this breakpoint's underlying marker.
 	 */
-	public void setPersisted(boolean registered) throws CoreException;	
+	public void setPersisted(boolean registered) throws CoreException;
+	
+	/**
+	 * Returns the name of the group this breakpoint belongs to
+	 * or <code>null</code> if none.
+	 * 
+	 * @return the name of the group this breakpoint belongs to or
+	 *  <code>null</code>.
+	 * @exception CoreException if unable to access the associated attribute
+	 *  on this breakpoint's underlying marker
+	 */
+	public String getGroup() throws CoreException;
+	
+	/**
+	 * Sets this breakpoint's group to the group with the given name or
+	 * <code>null</code> to set the group to none.
+	 * 
+	 * @param groupName the name of the group to which this breakpoint belongs 
+	 * @exception CoreException if unable to set the associated attribute on
+	 *  this breakpoint's underlying marker.
+	 */
+	public void setGroup(String groupName) throws CoreException;
 }
 
 
diff --git a/org.eclipse.debug.ui/icons/full/elcl16/dissolve_group.gif b/org.eclipse.debug.ui/icons/full/elcl16/dissolve_group.gif
new file mode 100644
index 0000000..d077125
--- /dev/null
+++ b/org.eclipse.debug.ui/icons/full/elcl16/dissolve_group.gif
Binary files differ
diff --git a/org.eclipse.debug.ui/icons/full/obj16/breakpoint_group.gif b/org.eclipse.debug.ui/icons/full/obj16/breakpoint_group.gif
new file mode 100644
index 0000000..173661c
--- /dev/null
+++ b/org.eclipse.debug.ui/icons/full/obj16/breakpoint_group.gif
Binary files differ
diff --git a/org.eclipse.debug.ui/plugin.xml b/org.eclipse.debug.ui/plugin.xml
index 1a648d8..4019403 100644
--- a/org.eclipse.debug.ui/plugin.xml
+++ b/org.eclipse.debug.ui/plugin.xml
@@ -664,6 +664,23 @@
                   class="org.eclipse.debug.core.model.IBreakpoint">
             </selection>
          </action>
+         <action
+               id="org.eclipse.debug.ui.breakpointsView.toolbar.setDefaultBreakpointGroup"
+               menubarPath="defaultBreakpointGroup"
+               class="org.eclipse.debug.internal.ui.actions.SetDefaultBreakpointGroupAction"
+               icon="icons/full/obj16/breakpoint_group.gif"
+               helpContextId="set_default_breakpoint_group_action_context"
+               label="Set Default Group..."
+               tooltip="Set Default Breakpoint Group">
+         </action>
+         <action
+               id="org.eclipse.debug.ui.breakpointsView.toolbar.clearDefaultBreakpointGroup"
+               menubarPath="defaultBreakpointGroup"
+               class="org.eclipse.debug.internal.ui.actions.ClearDefaultBreakpointGroupAction"
+               helpContextId="clear_default_breakpoint_group_action_context"
+               label="Clear Default Group"
+               tooltip="Clear Default Breakpoint Group">
+         </action>
       </viewContribution>
 <!-- Contributions to Expression View Toolbar -->
       <viewContribution
@@ -995,23 +1012,37 @@
             targetID="org.eclipse.debug.ui.BreakpointView"
             id="org.eclipse.debug.ui.breakpointview.popupMenu">
          <action
+               label="%SelectAll.label"
+               helpContextId="select_all_breakpoints_action_context"
+               class="org.eclipse.debug.internal.ui.actions.SelectAllBreakpointsAction"
+               menubarPath="breakpointNoSelectionGroup"
+               id="org.eclipse.debug.ui.actions.SelectAllBreakpointsAction">
+         </action>
+         <action
                label="%RemoveAllAction.label"
                icon="icons/full/elcl16/rem_all_co.gif"
                helpContextId="remove_all_breakpoints_action_context"
                class="org.eclipse.debug.internal.ui.actions.RemoveAllBreakpointsAction"
-               menubarPath="breakpointGroup"
+               menubarPath="breakpointNoSelectionGroup"
                id="org.eclipse.debug.ui.actions.RemoveAllBreakpoints">
          </action>
+      </viewerContribution>
+      <!-- Breakpoint actions -->
+      <viewerContribution
+            targetID="org.eclipse.debug.ui.BreakpointView"
+            id="org.eclipse.debug.ui.breakpointview.breakpointActions">
+         <visibility>
+            <objectClass
+               name="org.eclipse.debug.core.model.IBreakpoint">
+            </objectClass>
+         </visibility>
          <action
                label="%RemoveAction.label"
                icon="icons/full/elcl16/rem_co.gif"
                helpContextId="remove_breakpoint_action_context"
                class="org.eclipse.debug.internal.ui.actions.RemoveBreakpointAction"
-               menubarPath="breakpointGroup"
+               menubarPath="breakpointNoSelectionGroup"
                id="org.eclipse.debug.ui.actions.RemoveBreakpoint">
-            <selection
-                  class="org.eclipse.debug.core.model.IBreakpoint">
-            </selection>
          </action>
          <action
                label="%DisableBreakpointsAction.label"
@@ -1021,9 +1052,6 @@
                menubarPath="breakpointGroup"
                enablesFor="2+"
                id="org.eclipse.debug.ui.actions.DisableBreakpoint">
-            <selection
-                  class="org.eclipse.debug.core.model.IBreakpoint">
-            </selection>
          </action>
          <action
                label="%EnableBreakpointsAction.label"
@@ -1033,16 +1061,42 @@
                menubarPath="breakpointGroup"
                enablesFor="2+"
                id="org.eclipse.debug.ui.actions.EnableBreakpoint">
-            <selection
-                  class="org.eclipse.debug.core.model.IBreakpoint">
-            </selection>
          </action>
          <action
-               label="%SelectAll.label"
-               helpContextId="select_all_breakpoints_action_context"
-               class="org.eclipse.debug.internal.ui.actions.SelectAllBreakpointsAction"
+               label="Add To Group"
+               icon="icons/full/obj16/breakpoint_group.gif"
+               helpContextId="add_breakpoint_to_group_action_context"
+               class="org.eclipse.debug.internal.ui.actions.AddBreakpointToGroupAction"
                menubarPath="breakpointGroup"
-               id="org.eclipse.debug.ui.actions.SelectAllBreakpointsAction">
+               enablesFor="1+"
+               id="org.eclipse.debug.ui.actions.AddBreakpointToGroup">
+         </action>
+      </viewerContribution>
+      <!-- Breakpoint group actions -->
+      <viewerContribution
+            targetID="org.eclipse.debug.ui.BreakpointView"
+            id="org.eclipse.debug.ui.breakpointview.breakpointGroupActions">
+         <visibility>
+            <objectClass
+               name="java.lang.String">
+            </objectClass>
+         </visibility>
+         <action
+               label="Rename Group"
+               helpContextId="rename_breakpoint_group_action_context"
+               class="org.eclipse.debug.internal.ui.actions.RenameBreakpointGroupAction"
+               menubarPath="breakpointGroupGroup"
+               enablesFor="1+"
+               id="org.eclipse.debug.ui.actions.RenameBreakpointGroup">
+         </action>
+         <action
+               label="Dissolve Group"
+               icon="icons/full/elcl16/dissolve_group.gif"
+               helpContextId="dissolve_breakpoint_group_action_context"
+               class="org.eclipse.debug.internal.ui.actions.DissolveBreakpointGroupAction"
+               menubarPath="breakpointGroupGroup"
+               enablesFor="1+"
+               id="org.eclipse.debug.ui.actions.DissolveBreakpointGroup">
          </action>
       </viewerContribution>
 <!-- Contributions to Variables View Popup Menu -->
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugPluginImages.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugPluginImages.java
index 720bf64..1959e93 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugPluginImages.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/DebugPluginImages.java
@@ -150,6 +150,7 @@
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_REGISTER_GROUP, OBJECT + "genericreggroup_obj.gif"); //$NON-NLS-1$
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT, OBJECT + "brkp_obj.gif"); //$NON-NLS-1$
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_DISABLED, OBJECT + "brkpd_obj.gif"); //$NON-NLS-1$
+		declareRegistryImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_GROUP, OBJECT + "breakpoint_group.gif"); //$NON-NLS-1$
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_WATCHPOINT, OBJECT + "readwrite_obj.gif"); //$NON-NLS-1$
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_WATCHPOINT_DISABLED, OBJECT + "readwrite_obj_disabled.gif"); //$NON-NLS-1$
 		declareRegistryImage(IDebugUIConstants.IMG_OBJS_OS_PROCESS, OBJECT + "osprc_obj.gif"); //$NON-NLS-1$
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointGroupAction.java
new file mode 100644
index 0000000..50c2bd0
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointGroupAction.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+/**
+ * 
+ */
+public abstract class AbstractBreakpointGroupAction extends AbstractBreakpointsViewAction {
+
+    protected String[] fGroups;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+	 */
+	public void selectionChanged(IAction action, ISelection sel) {
+		IStructuredSelection selection= (IStructuredSelection) sel;
+		int selectionSize= selection.size();
+		if (selectionSize == 0) {
+		    fGroups= new String[0];
+		} else {
+			fGroups= new String[selection.size()];
+			Iterator iter = selection.iterator();
+			int index= 0;
+			while (iter.hasNext()) {
+			    Object element= iter.next();
+			    if (element instanceof String) {
+			        fGroups[index++]= (String) element;
+			    } else {
+			        fGroups= new String[0];
+			        break;
+			    }
+			}
+		}
+		action.setEnabled(fGroups.length > 0);
+	}
+	
+	public String[] getSelectedGroups() {
+	    return fGroups;
+	}
+	
+	public IBreakpoint[] getBreakpoints(String group) {
+	    Object[] children = fView.getTreeContentProvider().getChildren(group);
+	    IBreakpoint[] breakpoints= new IBreakpoint[children.length];
+	    for (int i = 0; i < children.length; i++) {
+            breakpoints[i]= (IBreakpoint) children[i];
+        }
+	    return breakpoints;
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointsViewAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointsViewAction.java
new file mode 100644
index 0000000..2dc18e4
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AbstractBreakpointsViewAction.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsView;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * 
+ */
+public abstract class AbstractBreakpointsViewAction implements IViewActionDelegate {
+    
+    protected BreakpointsView fView;
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
+     */
+    public void init(IViewPart view) {
+        fView= (BreakpointsView) view;
+    }
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AddBreakpointToGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AddBreakpointToGroupAction.java
new file mode 100644
index 0000000..158b622
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/AddBreakpointToGroupAction.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+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.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * 
+ */
+public class AddBreakpointToGroupAction implements IViewActionDelegate {
+	
+	private Object[] fBreakpoints= null;
+	private BreakpointsView fView= null;
+	
+	/**
+	 * A dialog that sets the focus to the text area.
+	 */
+	class BreakpointGroupDialog extends InputDialog {
+		
+		private Button fAutoAddToGroup;
+		
+		protected  BreakpointGroupDialog(Shell parentShell,
+									String dialogTitle,
+									String dialogMessage,
+									String initialValue,
+									IInputValidator validator) {
+			super(parentShell, dialogTitle, dialogMessage, initialValue, validator);
+		}
+		
+		
+		/**
+		 * @see Dialog#createDialogArea(Composite)
+		 */
+		protected Control createDialogArea(Composite parent) {
+			Composite area= (Composite)super.createDialogArea(parent);
+			
+			fAutoAddToGroup = new Button(area, SWT.CHECK);
+			GridData data = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL);
+			data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+			fAutoAddToGroup.setLayoutData(data);
+			fAutoAddToGroup.setFont(parent.getFont());
+			fAutoAddToGroup.setText("Automatically add new breakpoints to this group");
+			fAutoAddToGroup.setSelection(fView.getAutoGroup() != null);
+			
+			return area;
+		}
+		protected void okPressed() {
+		    fView.setAutoGroup(getValue());
+			super.okPressed();
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+	 */
+	public void run(IAction action) {
+		String initialValue= fView.getAutoGroup();
+		BreakpointGroupDialog dialog = new BreakpointGroupDialog(null, "Add To Group", "Specify the name of the group", initialValue, null);
+		int dialogResult = dialog.open();
+		if (dialogResult == Window.OK) {
+			String value= dialog.getValue();
+			if (value.equals("")) {
+				value= null;
+			}
+			try {
+				for (int i = 0; i < fBreakpoints.length; i++) {
+					((IBreakpoint) fBreakpoints[i]).setGroup(value);
+				}
+			} catch (CoreException e) {
+				DebugUIPlugin.errorDialog(dialog.getShell(), "Error Adding To Group", "An exception occurred while attempting to add the breakpoint to the specified group.", e);
+			}
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
+	 */
+	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+	 */
+	public void selectionChanged(IAction action, ISelection sel) {
+		IStructuredSelection selection= (IStructuredSelection) sel;
+		Iterator iterator = selection.iterator();
+		while (iterator.hasNext()) {
+			if (!(iterator.next() instanceof IBreakpoint)) {
+				action.setEnabled(false);
+				fBreakpoints= null;
+				return;
+			}
+		}
+		action.setEnabled(true);
+		fBreakpoints= selection.toArray();
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
+	 */
+	public void init(IViewPart view) {
+		fView= (BreakpointsView) view;
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ClearDefaultBreakpointGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ClearDefaultBreakpointGroupAction.java
new file mode 100644
index 0000000..047e92c
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ClearDefaultBreakpointGroupAction.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * 
+ */
+public class ClearDefaultBreakpointGroupAction extends AbstractBreakpointsViewAction {
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+     */
+    public void run(IAction action) {
+        fView.setAutoGroup(null);
+    }
+
+    /* (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/DissolveBreakpointGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/DissolveBreakpointGroupAction.java
new file mode 100644
index 0000000..6e0fd37
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/DissolveBreakpointGroupAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.action.IAction;
+
+/**
+ * An action that removes all breakpoints from a group.
+ */
+public class DissolveBreakpointGroupAction extends AbstractBreakpointGroupAction {
+    
+    public DissolveBreakpointGroupAction() {
+    }
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+	 */
+	public void run(IAction action) {
+	    String[] groups = getSelectedGroups();
+	    for (int i = 0; i < groups.length; i++) {
+	        IBreakpoint[] breakpoints = getBreakpoints(groups[i]);
+	        for (int j = 0; j < breakpoints.length; j++) {
+                try {
+                    breakpoints[j].setGroup(null);
+                } catch (CoreException e) {
+                }
+            }
+        }
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/OpenBreakpointMarkerAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/OpenBreakpointMarkerAction.java
index a2572d5..fbd42bb 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/OpenBreakpointMarkerAction.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/OpenBreakpointMarkerAction.java
@@ -82,17 +82,19 @@
 	 */
 	public void selectionChanged(IStructuredSelection sel) {
 		if (sel.size() == 1) {
-			breakpoint= (IBreakpoint)sel.getFirstElement();
-			input= fgPresentation.getEditorInput(breakpoint);
-			if (input != null) {
-				setEnabled(true);
-			} else {
-				setEnabled(false);
+			Object element = sel.getFirstElement();
+			if (element instanceof IBreakpoint) {
+				breakpoint= (IBreakpoint) element;
+				input= fgPresentation.getEditorInput(breakpoint);
+				if (input != null) {
+					setEnabled(true);
+					return;
+				}
 			}
 		} else {
 			breakpoint = null;
 			input = null;
-			setEnabled(false);
 		}
+		setEnabled(false);
 	}
 }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/RenameBreakpointGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/RenameBreakpointGroupAction.java
new file mode 100644
index 0000000..581f8f0
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/RenameBreakpointGroupAction.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.InputDialog;
+
+/**
+ * An action which renames a breakpoint group.
+ */
+public class RenameBreakpointGroupAction extends AbstractBreakpointGroupAction {
+	
+	public RenameBreakpointGroupAction() {
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+	 */
+	public void run(IAction action) {
+		String[] groups= getSelectedGroups();
+		for (int i = 0; i < groups.length; i++) {
+		    String group= groups[i];
+		    InputDialog dialog= new InputDialog(fView.getViewSite().getShell(), "Rename Group", "Specify the new name for the group:", group, null);
+			if (dialog.open() != Dialog.OK) {
+				return;
+			}
+			String newGroup = dialog.getValue();
+	        IBreakpoint[] breakpoints = getBreakpoints(group);
+			for (int j = 0; j < breakpoints.length; j++) {
+				try {
+					breakpoints[j].setGroup(newGroup);
+				} catch (CoreException e) {
+				}
+			}
+        }
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/SetDefaultBreakpointGroupAction.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/SetDefaultBreakpointGroupAction.java
new file mode 100644
index 0000000..9797f6a
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/SetDefaultBreakpointGroupAction.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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 implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.debug.internal.ui.DebugPluginImages;
+import org.eclipse.debug.internal.ui.SWTUtil;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+
+/**
+ * 
+ */
+public class SetDefaultBreakpointGroupAction extends AbstractBreakpointsViewAction {
+    
+    private class SetDefaultGroupDialog extends InputDialog {
+
+        public SetDefaultGroupDialog(Shell parentShell, String dialogTitle, String dialogMessage, String initialValue, IInputValidator validator) {
+            super(parentShell, dialogTitle, dialogMessage, initialValue, validator);
+        }
+        
+        /**
+		 * @see Dialog#createDialogArea(Composite)
+		 */
+		protected Control createDialogArea(Composite parent) {
+			Composite area= (Composite) super.createDialogArea(parent);
+			
+			Button button= SWTUtil.createPushButton(area, "Browse...", null);
+			GridData data= (GridData) button.getLayoutData();
+			data.horizontalAlignment= GridData.BEGINNING;
+			data.verticalAlignment= GridData.BEGINNING;
+			button.addSelectionListener(new SelectionAdapter() {
+                public void widgetSelected(SelectionEvent e) {
+                    ListSelectionDialog dialog= new ListSelectionDialog(
+                        getShell(),
+                        new Object(),
+                        new IStructuredContentProvider() {
+	                        public Object[] getElements(Object inputElement) {
+	                            Object[] children = fView.getTreeContentProvider().getElements(fView.getViewer().getInput());
+	                            List groups= new ArrayList();
+	                            for (int i = 0; i < children.length; i++) {
+                                    Object child= children[i];
+                                    if (child instanceof String) {
+                                        groups.add(child);
+                                    }
+                                }
+	                            return groups.toArray();
+	                        }
+	                        public void dispose() {
+	                        }
+	                        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+	                        }
+                        },
+                        new LabelProvider() {
+	                        public Image getImage(Object element) {
+	                            return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_GROUP);
+	                        }
+	
+	                        public String getText(Object element) {
+	                            return (String) element;
+	                        }
+                        },
+                    	"Select a group");
+                    if (dialog.open() != Dialog.OK) {
+                        return;
+                    }
+                    Object[] result = dialog.getResult();
+                    getText().setText((String) result[0]);
+                }
+            });
+			
+			return area;
+		}
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+     */
+    public void run(IAction action) {
+        String currentGroup= fView.getAutoGroup();
+        if (currentGroup == null) {
+            currentGroup= "";
+        }
+        InputDialog dialog= new SetDefaultGroupDialog(fView.getViewSite().getShell(), "Set Default Group", "Specify the group in which new breakpoints will be automatically placed:", currentGroup, null);
+        if (dialog.open() != Dialog.OK) {
+            return;
+        }
+        String group= dialog.getValue();
+        fView.setAutoGroup(group);
+    }
+
+    /* (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/views/breakpoints/BreakpointsSorter.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/breakpoints/BreakpointsSorter.java
index af96e56..79e4311 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,6 +49,15 @@
 		 *  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);
+				}
+				return -1;
+			} else if (e2 instanceof String) {
+				return 1;
+			}
 	
 			IBreakpoint b1= (IBreakpoint)e1;
 			IBreakpoint b2= (IBreakpoint)e2;
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 41fbb54..b12326d 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
@@ -23,6 +23,7 @@
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IThread;
+import org.eclipse.debug.internal.ui.DebugPluginImages;
 import org.eclipse.debug.internal.ui.DebugUIPlugin;
 import org.eclipse.debug.internal.ui.DelegatingModelPresentation;
 import org.eclipse.debug.internal.ui.IDebugHelpContextIds;
@@ -38,18 +39,21 @@
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.jface.viewers.CheckStateChangedEvent;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
 import org.eclipse.jface.viewers.ICheckStateListener;
 import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeViewerListener;
 import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.ui.IMemento;
 import org.eclipse.ui.ISelectionListener;
 import org.eclipse.ui.IWorkbenchActionConstants;
@@ -70,6 +74,7 @@
 	// Persistance constants
 	private static String KEY_IS_TRACKING_SELECTION= "isTrackingSelection"; //$NON-NLS-1$
 	private static String KEY_VALUE="value"; //$NON-NLS-1$
+	private String fAutoGroup;
 	
 	/**
 	 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
@@ -87,12 +92,26 @@
 	 * @see AbstractDebugView#createViewer(Composite)
 	 */
 	protected Viewer createViewer(Composite parent) {
-		CheckboxTableViewer viewer = CheckboxTableViewer.newCheckList(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+		CheckboxTreeViewer viewer = new CheckboxTreeViewer(new Tree(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CHECK));
 		viewer.setContentProvider(new BreakpointsViewContentProvider());
-		viewer.setLabelProvider(new DelegatingModelPresentation());
+		viewer.setLabelProvider(new DelegatingModelPresentation() {
+			public Image getImage(Object item) {
+				if (item instanceof String) {
+					return DebugPluginImages.getImage(IDebugUIConstants.IMG_OBJS_BREAKPOINT_GROUP);
+				}
+				return super.getImage(item);
+			}
+		});
 		viewer.setSorter(new BreakpointsSorter());
 		viewer.setInput(DebugPlugin.getDefault().getBreakpointManager());
 		viewer.addCheckStateListener(fCheckListener);
+		viewer.addTreeListener(new ITreeViewerListener() {
+			public void treeExpanded(TreeExpansionEvent event) {
+				initializeCheckedState();
+			}
+			public void treeCollapsed(TreeExpansionEvent event) {
+			}
+		});
 		// Necessary so that the PropertySheetView hears about selections in this view
 		getSite().setSelectionProvider(viewer);
 		initIsTrackingSelection();
@@ -121,8 +140,9 @@
 	 */
 	public void initializeCheckedState() {
 		IBreakpointManager manager= DebugPlugin.getDefault().getBreakpointManager();
-		final CheckboxTableViewer viewer= getCheckboxViewer();
-		Object[] elements= ((IStructuredContentProvider) viewer.getContentProvider()).getElements(manager);
+		CheckboxTreeViewer viewer= getCheckboxViewer();
+		ITreeContentProvider provider= getTreeContentProvider();
+		Object[] elements= provider.getElements(manager);
 		ArrayList breakpoints= new ArrayList(elements.length);
 		for (int i = 0; i < elements.length; i++) {
 			breakpoints.add(elements[i]);
@@ -130,8 +150,27 @@
 		ListIterator iterator= breakpoints.listIterator();
 		while (iterator.hasNext()) {
 			try {
-				if (!((IBreakpoint) iterator.next()).isEnabled()) {
+				Object element= iterator.next();
+				if (element instanceof IBreakpoint && !((IBreakpoint) element).isEnabled()) {
 					iterator.remove();
+				} else if (element instanceof String) {
+					Object[] children = provider.getChildren(element);
+					int enabledChildren= 0;
+					for (int i = 0; i < children.length; i++) {
+						IBreakpoint child = (IBreakpoint) children[i];
+						if (child.isEnabled()) {
+							iterator.add(child);
+							enabledChildren++;
+						}
+					}
+					if (enabledChildren != children.length && enabledChildren > 0) {
+						// If some but not all children are enabled, gray the group node
+						viewer.setGrayed(element, true);
+					} else if (enabledChildren == 0) {
+						// Uncheck the group node if no children are enabled
+						iterator.remove();
+						viewer.setGrayed(element, false);
+					}
 				}
 			} catch (CoreException e) {
 				DebugUIPlugin.log(e);
@@ -139,14 +178,43 @@
 		}
 		viewer.setCheckedElements(breakpoints.toArray());
 	}
+	
+	/**
+	 * Sets the group that new breakpoints will automatically be
+	 * added to.
+	 * @param group the group name
+	 */
+	public void setAutoGroup(String group) {
+	    if (group.length() < 1) {
+	        group= null;
+	    }
+		fAutoGroup= group;
+	}
+	
+	/**
+	 * Returns the group that new breakpoints will be automatically
+	 * added to.
+	 * @return the group that new breakpoints will be automatically
+	 *  added to
+	 */
+	public String getAutoGroup() {
+		return fAutoGroup;
+	}
 		
 	/**
-	 * Returns this view's viewer as a checkbox table viewer.
-	 * 
-	 * @return
+	 * Returns this view's viewer as a checkbox tree viewer.
+	 * @return this view's viewer as a checkbox tree viewer
 	 */
-	private CheckboxTableViewer getCheckboxViewer() {
-		return (CheckboxTableViewer) getViewer();
+	public CheckboxTreeViewer getCheckboxViewer() {
+		return (CheckboxTreeViewer) getViewer();
+	}
+	
+	/**
+	 * Returns this view's content provider as a tree content provider.
+	 * @return this view's content provider as a tree content provider
+	 */
+	public ITreeContentProvider getTreeContentProvider() {
+	    return (ITreeContentProvider) getCheckboxViewer().getContentProvider();
 	}
 
 	/**
@@ -157,24 +225,75 @@
 	 */
 	private void handleCheckStateChanged(CheckStateChangedEvent event) {
 		Object source= event.getElement();
-		if (!(source instanceof IBreakpoint)) {
-			return;
+		if (source instanceof String) {
+			handleGroupChecked(event, (String) source);
+		} else if (source instanceof IBreakpoint) {
+			handleBreakpointChecked(event, (IBreakpoint) source);
 		}
-		IBreakpoint breakpoint= (IBreakpoint) source;
+	}
+	/**
+	 * A breakpoint has been checked/unchecked. Update the group
+	 * element's checked/grayed state as appropriate.
+	 */
+	private void handleBreakpointChecked(CheckStateChangedEvent event, IBreakpoint breakpoint) {
 		boolean enable= event.getChecked();
+		CheckboxTreeViewer viewer= getCheckboxViewer();
+		ITreeContentProvider contentProvider= getTreeContentProvider();
 		try {
 			breakpoint.setEnabled(enable);
-			getCheckboxViewer().refresh(breakpoint);
+			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)
+				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);
+					}
+				}
+			}
+			viewer.update(breakpoint, null);
 		} catch (CoreException e) {
 			String titleState= enable ? DebugUIViewsMessages.getString("BreakpointsView.6") : DebugUIViewsMessages.getString("BreakpointsView.7"); //$NON-NLS-1$ //$NON-NLS-2$
 			String messageState= enable ? DebugUIViewsMessages.getString("BreakpointsView.8") : DebugUIViewsMessages.getString("BreakpointsView.9");  //$NON-NLS-1$ //$NON-NLS-2$
 			DebugUIPlugin.errorDialog(DebugUIPlugin.getShell(), MessageFormat.format(DebugUIViewsMessages.getString("BreakpointsView.10"), new String[] { titleState }), MessageFormat.format(DebugUIViewsMessages.getString("BreakpointsView.11"), new String[] { messageState }), e); //$NON-NLS-1$ //$NON-NLS-2$
 			// If the breakpoint fails to update, reset its check state.
 			getCheckboxViewer().removeCheckStateListener(fCheckListener);
-			event.getCheckable().setChecked(source, !event.getChecked());
+			event.getCheckable().setChecked(breakpoint, !event.getChecked());
 			getCheckboxViewer().addCheckStateListener(fCheckListener);
 		}
 	}
+
+	/**
+	 * 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) {
+		CheckboxTreeViewer viewer= getCheckboxViewer();
+		Object[] children = getTreeContentProvider().getChildren(group);
+		boolean enable= event.getChecked();
+		viewer.setGrayed(group, false);
+		
+		DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(getEventHandler());
+		for (int i = 0; i < children.length; i++) {
+			IBreakpoint breakpoint= (IBreakpoint) children[i];
+			try {
+				viewer.setChecked(breakpoint, enable);
+				breakpoint.setEnabled(enable);
+				viewer.update(breakpoint, null);
+			} catch (CoreException e) {
+				DebugUIPlugin.log(e);
+			}
+		}
+		DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(getEventHandler());
+		
+		return;
+	}
+
 	/**
 	 * @see AbstractDebugView#getHelpContextId()
 	 */
@@ -356,13 +475,13 @@
 			color= DebugUIPlugin.getStandardDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
 			enabled = false;
 		}
-		Table table = getCheckboxViewer().getTable();
-		TableItem[] items = table.getItems();
+		Tree tree = getCheckboxViewer().getTree();
+		TreeItem[] items = tree.getItems();
 		for (int i = 0; i < items.length; i++) {
 			items[i].setBackground(color);
 			items[i].setGrayed(!enabled);
 		}
-		table.setBackground(color);
+		tree.setBackground(color);
 		if (enabled) {
 			setContentDescription(""); //$NON-NLS-1$
 		} else {
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 9ccf23c..7261844 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
@@ -10,17 +10,46 @@
  *******************************************************************************/
 package org.eclipse.debug.internal.ui.views.breakpoints;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.IBreakpointManager;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.Viewer;
 
-public class BreakpointsViewContentProvider implements IStructuredContentProvider {
+public class BreakpointsViewContentProvider implements ITreeContentProvider {
+	
+	private Map elements= new HashMap();
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
 	 */
 	public Object[] getElements(Object parent) {
-		return ((IBreakpointManager) parent).getBreakpoints();
+		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);
+			} else {
+				elements.put(breakpoint, null);
+			}
+		}
+		return elements.keySet().toArray();
 	}
 
 	/* (non-Javadoc)
@@ -33,5 +62,39 @@
 	 * @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();
+	}
+
+	/* (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((String) parentElement);
+			if (list != null) {
+				return list.toArray();
+			}
+		}
+		return null;
+	}
+
+	/* (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;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
+	 */
+	public boolean hasChildren(Object element) {
+		return element instanceof String;
 	}
 }
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 280b82c..89b9798 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
@@ -22,8 +22,7 @@
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.debug.internal.ui.DebugUIPlugin;
 import org.eclipse.debug.internal.ui.views.DebugUIViewsMessages;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.activities.ActivityManagerEvent;
 import org.eclipse.ui.activities.IActivityManagerListener;
@@ -68,7 +67,38 @@
 			fView.asyncExec(new Runnable() {
 				public void run() {
 					if (fView.isAvailable()) {
-						CheckboxTableViewer viewer = (CheckboxTableViewer)fView.getViewer();
+						String autoGroup= fView.getAutoGroup();
+						if (autoGroup != null) {
+						    // Add any new breakpoints to the "default group"
+							for (int i = 0; i < breakpoints.length; i++) {
+								try {
+									breakpoints[i].setGroup(autoGroup);
+								} catch (CoreException e) {
+								}
+							}
+						}
+						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];
@@ -76,7 +106,6 @@
 							if (!DebugPlugin.getDefault().getBreakpointManager().isRegistered(breakpoint)) {
 								continue;
 							}
-							viewer.add(breakpoint);
 							try {
 								boolean enabled= breakpoint.isEnabled();
 								if (viewer.getChecked(breakpoint) != enabled) {
@@ -109,20 +138,8 @@
 			fView.asyncExec(new Runnable() {
 				public void run() {
 					if (fView.isAvailable()) {
-						TableViewer viewer= (TableViewer)fView.getViewer();
-						int[] indices= viewer.getTable().getSelectionIndices();
-						viewer.getControl().setRedraw(false);
-						viewer.remove(breakpoints);
-						viewer.getControl().setRedraw(true);
-						if (viewer.getSelection().isEmpty()) {
-							if (indices.length > 0) {
-								int index= indices[0];
-								viewer.getTable().select(Math.min(index, viewer.getTable().getItemCount() - 1));
-							}
-							//fire the selection changed as does not occur when
-							//setting selection on the swt widget
-							viewer.setSelection(viewer.getSelection());
-						}
+						CheckboxTreeViewer viewer= (CheckboxTreeViewer)fView.getViewer();
+						viewer.refresh();
 						fView.updateObjects();
 					}
 				}
@@ -133,31 +150,58 @@
 	/**
 	 * @see IBreakpointsListener#breakpointsChanged(IBreakpoint[], IMarkerDelta[])
 	 */
-	public void breakpointsChanged(final IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
+	public void breakpointsChanged(final IBreakpoint[] breakpoints, final IMarkerDelta[] deltas) {
 		if (fView.isAvailable() & fView.isVisible()) {
 			fView.asyncExec(new Runnable() {
 				public void run() {
 					if (fView.isAvailable()) {
-						CheckboxTableViewer viewer = (CheckboxTableViewer)fView.getViewer(); 
-						viewer.getControl().setRedraw(false);
+						CheckboxTreeViewer viewer = (CheckboxTreeViewer)fView.getViewer(); 
+						boolean refreshCheckedState= false;
 						for (int i = 0; i < breakpoints.length; i++) {
 							IBreakpoint breakpoint = breakpoints[i];
 							IMarker marker= breakpoint.getMarker();
 							if (marker != null && marker.exists()) {
-								// only refresh if still exists
+								IMarkerDelta delta= deltas[i];
+								if (delta != null) {
+									String oldGroup= (String) delta.getAttribute(IBreakpoint.GROUP);
+									String newGroup= null;
+									try {
+										newGroup= breakpoint.getGroup();
+									} catch (CoreException e1) {
+									}
+									boolean needsRefresh= false;
+									if (newGroup != oldGroup) { // new == old if they're both null
+										if (newGroup == null || oldGroup == null) {
+											// one is null, one isn't => changed
+											needsRefresh= true;
+										} else { // moved from one group to another ?
+											needsRefresh= !newGroup.equals(oldGroup);
+										}
+									}
+									if (needsRefresh) {
+										// If the group has changed, completely refresh the view to
+										// pick up structural changes.
+										fView.getViewer().refresh();
+										fView.initializeCheckedState();
+										return;
+									}
+								}
 								try {
 									boolean enabled= breakpoint.isEnabled();
 									if (viewer.getChecked(breakpoint) != enabled) {
-										viewer.setChecked(breakpoint, breakpoint.isEnabled());								
+										refreshCheckedState= true;
+										viewer.setChecked(breakpoint, breakpoint.isEnabled());
+										viewer.update(breakpoint, null);							
 									}
 								} catch (CoreException e) {
 									DebugUIPlugin.errorDialog(DebugUIPlugin.getShell(), DebugUIViewsMessages.getString("BreakpointsViewEventHandler.1"), DebugUIViewsMessages.getString("BreakpointsViewEventHandler.2"), e); //$NON-NLS-1$ //$NON-NLS-2$
 									DebugUIPlugin.log(e);
 								}
-								viewer.refresh(breakpoint);
 							}
 						}
-						viewer.getControl().setRedraw(true);
+						if (refreshCheckedState) {
+							fView.initializeCheckedState();
+						}
 						fView.updateObjects();
 					}
 				}
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 a5b3435..6f28597 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
@@ -397,6 +397,9 @@
 	
 	/** Disabled breakpoint image identifier. */
 	public static final String IMG_OBJS_BREAKPOINT_DISABLED= "IMG_OBJS_BREAKPOINT_DISABLED"; //$NON-NLS-1$
+	
+	/** Breakpoint group image identifier. */
+	public static final String IMG_OBJS_BREAKPOINT_GROUP = "IMG_OBJS_BREAKPOINT_GROUP"; //$NON-NLS-1$
 		
 	/**
 	 * Enabled watchpoint image identifier.