This commit was manufactured by cvs2svn to create branch
'viewer_rework_3_3'.

Cherrypick from master 2006-11-08 14:37:40 UTC Michael Rennie <mrennie> 'further update to a bug I apparently already fixed....':
    org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java
    org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java
new file mode 100644
index 0000000..f565c73
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationFilteredTree.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.launchConfigurations;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.ILaunchGroup;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.HelpEvent;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.model.WorkbenchViewerComparator;
+
+/**
+ * Overrides the default filterd tree to use our own tree viewer which supports preserving selection after filtering
+ * @since 3.3 
+ */
+public final class LaunchConfigurationFilteredTree extends FilteredTree {
+
+	private ILaunchGroup fLaunchGroup = null;
+	private ViewerFilter[] fFilters = null;
+	private int fTreeStyle = -1;
+	private PatternFilter fPatternFilter = null;
+	
+	/**
+	 * Constructor
+	 * @param parent
+	 * @param treeStyle
+	 * @param filter
+	 */
+	public LaunchConfigurationFilteredTree(Composite parent, int treeStyle, PatternFilter filter, ILaunchGroup group, ViewerFilter[] filters) {
+		super(parent, treeStyle, filter);
+		fLaunchGroup = group;
+		fFilters = filters;
+		fPatternFilter = filter;
+		fTreeStyle = treeStyle;
+	}
+	
+	/**
+	 * @see org.eclipse.ui.dialogs.FilteredTree#doCreateTreeViewer(org.eclipse.swt.widgets.Composite, int)
+	 */
+	protected TreeViewer doCreateTreeViewer(Composite cparent, int style) {
+		treeViewer = new LaunchConfigurationViewer(cparent, style);
+		treeViewer.setLabelProvider(DebugUITools.newDebugModelPresentation());
+		treeViewer.setComparator(new WorkbenchViewerComparator());
+		treeViewer.setContentProvider(new LaunchConfigurationTreeContentProvider(fLaunchGroup.getMode(), cparent.getShell()));
+		treeViewer.addFilter(new LaunchGroupFilter(fLaunchGroup));
+		treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
+		if(fFilters != null) {
+			for (int i = 0; i < fFilters.length; i++) {
+				treeViewer.addFilter(fFilters[i]);
+			}
+		}
+		treeViewer.getControl().addHelpListener(new HelpListener() {
+			public void helpRequested(HelpEvent evt) {
+				handleHelpRequest(evt);
+			}
+		});
+		return treeViewer;
+	}
+	
+	/**
+	 * @see org.eclipse.ui.dialogs.FilteredTree#createControl(org.eclipse.swt.widgets.Composite, int)
+	 */
+	protected void createControl(Composite cparent, int treeStyle) {
+		super.createControl(cparent, treeStyle);
+		setBackground(cparent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+	}
+
+	/**
+	 * @see org.eclipse.ui.dialogs.FilteredTree#init(int, org.eclipse.ui.dialogs.PatternFilter)
+	 * force it to do nothing so that we can initialize the class properly
+	 */
+	protected void init(int treeStyle, PatternFilter filter) {}
+
+	/**
+	 * This method is used to create the actual set of controls for the dialog
+	 */
+	public void createViewControl() {
+		super.init(fTreeStyle, fPatternFilter);
+	}
+	
+	/**
+	 * Handle help events locally rather than deferring to WorkbenchHelp.  This
+	 * allows help specific to the selected config type to be presented.
+	 * 
+	 * @since 2.1
+	 */
+	protected void handleHelpRequest(HelpEvent evt) {
+		if (getViewer().getTree() != evt.getSource()) {
+			return;
+		}
+		String id = computeContextId();
+		if (id!=null)
+			PlatformUI.getWorkbench().getHelpSystem().displayHelp(id);
+	}
+	
+	/**
+	 * Computes the context id for this viewer
+	 * @return the context id
+	 */
+	public String computeContextId() {
+		try {
+			ISelection selection = getViewer().getSelection();
+			if (!selection.isEmpty() && selection instanceof IStructuredSelection ) {
+				IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+				Object firstSelected = structuredSelection.getFirstElement();
+				ILaunchConfigurationType configType = null;
+				if (firstSelected instanceof ILaunchConfigurationType) {
+					configType = (ILaunchConfigurationType) firstSelected;
+				} 
+				else if (firstSelected instanceof ILaunchConfiguration) {
+					configType = ((ILaunchConfiguration) firstSelected).getType();
+				}
+				if (configType != null) {
+					String helpContextId = LaunchConfigurationPresentationManager.getDefault().getHelpContext(configType, fLaunchGroup.getMode());
+					if (helpContextId != null) {
+						return helpContextId;
+					}
+				}
+			}
+		} 
+		catch (CoreException ce) {DebugUIPlugin.log(ce);}
+		return null;
+	}
+	
+	/**
+	 * Returns the launch configuration viewer for this filtered tree
+	 * @return the treeviewer appropriately cast
+	 */
+	public LaunchConfigurationViewer getLaunchConfigurationViewer() {
+		return (LaunchConfigurationViewer) getViewer();
+	}
+
+}
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java
new file mode 100644
index 0000000..f863923
--- /dev/null
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationViewer.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.internal.ui.launchConfigurations;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * This class allow the notion of the viewer to be abstracted from the launch configuration view, as well as allowing the over-riding of 
+ * selection preservation when filtering/deletion occurs
+ * @since 3.3
+ */
+public class LaunchConfigurationViewer extends TreeViewer {
+
+	/**
+	 * Constructor
+	 * @param tree the tree to create the viewer on
+	 */
+	public LaunchConfigurationViewer(Tree tree) {
+		super(tree);
+	}
+	
+	/**
+	 * Constructor
+	 * @param parent
+	 * @param style
+	 */
+	public LaunchConfigurationViewer(Composite parent, int style) {
+		this(new Tree(parent, style));
+	}
+
+	/**
+	 * @see org.eclipse.jface.viewers.StructuredViewer#preservingSelection(java.lang.Runnable)
+	 */
+	protected void preservingSelection(Runnable updateCode) {
+		IStructuredSelection selection = (IStructuredSelection) getSelection();
+		if(!selection.isEmpty()) {
+			int[] indices = collectIndices(selection.getFirstElement());
+			updateCode.run();
+			ArrayList set = new ArrayList();
+			Object o = null;
+			for(Iterator iter = selection.iterator(); iter.hasNext();) {
+				o = iter.next();
+				if(internalGetWidgetToSelect(o) != null) {
+					if(!set.contains(o)) {
+						set.add(o);
+					}
+				}
+			}
+			if(set.isEmpty()) {
+				//make a new selection based on the first item in the structured selection
+				Tree tree = getTree();
+				if(tree.getItemCount() > 0) {
+					int index = selectIndex(tree.getItemCount(), indices[0]);
+					if(index > -1) {
+						o = tree.getItem(index).getData();
+					}
+					else {
+						//parent index exists, so select child
+						TreeItem pitem = tree.getItem(indices[0]); 
+						o = pitem.getData();
+						//pick best child, or default to parent
+						index = selectIndex(pitem.getItemCount(), indices[1]);
+						if(index > -1) {
+							o = pitem.getItem(index);
+						}
+						else {
+							if(pitem.getItemCount() > 0) {
+								o = pitem.getItem((indices[1]-1 > -1 ? indices[1]-1 : 0)).getData();
+							}
+						}
+					}
+					if(!set.contains(o)) {
+						set.add(o);
+					}
+				}
+			}
+			setSelection(new StructuredSelection(set), true);
+		}
+		else {
+			super.preservingSelection(updateCode);
+		}
+	}
+	
+	/**
+	 * Covers the case of an outlier indice
+	 * @param count the count to compare the index to
+	 * @param index the index to compare against the count
+	 * @return the adjusted index in the event index is an outlier, or -1 if it falls within the 'count' range
+	 */
+	private int selectIndex(int count, int index) {
+		if(index > count-1) {
+			return count-1;
+		}
+		if(index < 0) {
+			return 0;
+		}
+		return -1;
+	}
+	
+	/**
+	 * Collects the indices of the child and parent items for the specified element
+	 * @param object the element to collect indices for
+	 * @return an array of indices for the specified element
+	 */
+	private int[] collectIndices(Object object) {
+		int[] indices = {-1, -1};
+		if(object != null) {
+			TreeItem item = (TreeItem) findItem(object);
+			if(item != null) {
+				TreePath path = getTreePathFromItem(item); 
+				item = (TreeItem) findItem(path.getFirstSegment());
+				if(item != null) {
+					indices[0] = getTree().indexOf(item);
+					if(path.getSegmentCount() == 2) {
+						indices[1] = indexOf(item.getItems(), path.getLastSegment());
+					}
+				}
+			}
+		}
+		return indices;
+	}
+	
+	/**
+	 * Finds the index of the specified object in the given array of tree items
+	 * @param items the items to search for the specified object
+	 * @param object the object to find the index of
+	 * @return the index of the specified object inthe listing of tree items, or -1 if not found
+	 */
+	private int indexOf(TreeItem[] items, Object object) {
+		if(object != null) {
+			for(int i = 0; i < items.length; i++) {
+				if(object.equals(items[i].getData())) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+}