Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 6caaed1dc7906a736f6cf6f9e06fde1a373c0818 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                          


                                                                       
                                                           


                                         
  


















                                                                                  
































                                                                                     
                                                                              
        
  
             


















































                                                                                                                                
                                                                                                      








                                                                                                                                              
                                                                                                











                                                                                                                                           
                                                                                                                       




                                                                 
                                                                                                  

















                                                                                                                                         
         
 
                                                                                                               



















































































































































































































                                                                                                                                                                          
 
/*******************************************************************************
 * Copyright (c) 2006, 2012 Wind River Systems and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Wind River Systems - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.dsf.debug.ui.viewmodel.breakpoints;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointsListener;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer;
import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants;
import org.eclipse.debug.internal.ui.breakpoints.provisional.OtherBreakpointCategory;
import org.eclipse.debug.internal.ui.elements.adapters.DefaultBreakpointsViewInput;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IBreakpointOrganizerDelegate;
import org.eclipse.debug.ui.contexts.DebugContextEvent;
import org.eclipse.debug.ui.contexts.IDebugContextListener;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.ui.IWorkbenchWindow;

/**
 * The breakpoint provider is used to populate the contents of the breakpoints
 * view.
 *
 * @since 2.1
 */
public class BreakpointVMProvider extends AbstractVMProvider {
	private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() {
		@Override
		public void propertyChange(PropertyChangeEvent event) {
			handleEventInExecThread(event);
		}
	};

	private IBreakpointsListener fBreakpointsListener = new IBreakpointsListener() {
		@Override
		public void breakpointsRemoved(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
			handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.REMOVED, breakpoints));
		}

		@Override
		public void breakpointsChanged(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) {
			handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.CHANGED, breakpoints));
		}

		@Override
		public void breakpointsAdded(IBreakpoint[] breakpoints) {
			handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.ADDED, breakpoints));
		}

	};

	private IDebugContextListener fDebugContextListener = new IDebugContextListener() {
		@Override
		public void debugContextChanged(final DebugContextEvent event) {
			handleEventInExecThread(event);
		}
	};

	private class ContainerBreakpointsCache extends DataCache<List<BreakpointOrganizerVMContext>> {

		private BreakpointOrganizerVMNode fOrganizerVMNode;
		private TreePath fParentPath;

		public ContainerBreakpointsCache(BreakpointOrganizerVMNode organizerVMNode, TreePath parentPath) {
			super(getExecutor());
			fOrganizerVMNode = organizerVMNode;
			fParentPath = parentPath;
		}

		@Override
		protected void retrieve(final DataRequestMonitor<List<BreakpointOrganizerVMContext>> rm) {
			getNestingCategoryBreakpoints(fParentPath, new DataRequestMonitor<IBreakpoint[]>(getExecutor(), rm) {
				@SuppressWarnings({ "cast", "unchecked" })
				@Override
				protected void handleSuccess() {
					Map<IAdaptable, List<IBreakpoint>> bpsLists = new HashMap<>();
					for (IBreakpoint bp : getData()) {
						IAdaptable[] bpCategories = fOrganizerVMNode.getOrganizer().getCategories(bp);
						if (bpCategories == null || bpCategories.length == 0) {
							bpCategories = OtherBreakpointCategory.getCategories(fOrganizerVMNode.getOrganizer());
						}

						for (IAdaptable category : bpCategories) {
							List<IBreakpoint> categoryBPs = bpsLists.get(category);
							if (categoryBPs == null) {
								categoryBPs = new ArrayList<>();
								bpsLists.put(category, categoryBPs);
							}
							categoryBPs.add(bp);
						}
					}

					// Only show the empty containers for the top-level node.
					if (fParentPath.getSegmentCount() == 0) {
						final IAdaptable[] independentCategories = fOrganizerVMNode.getOrganizer().getCategories();
						if (independentCategories != null) {
							for (IAdaptable category : independentCategories) {
								if (!bpsLists.containsKey(category)) {
									bpsLists.put(category, Collections.EMPTY_LIST);
								}
							}
						}
					}

					List<BreakpointOrganizerVMContext> vmcs = new ArrayList<>(
							bpsLists.size());
					for (Map.Entry<IAdaptable, List<IBreakpoint>> entry : bpsLists.entrySet()) {
						List<IBreakpoint> bpsList = entry.getValue();
						IBreakpoint[] bpsArray = bpsList.toArray(new IBreakpoint[bpsList.size()]);

						vmcs.add(createBreakpointOrganizerVMContext(fOrganizerVMNode, entry.getKey(), bpsArray));
					}
					Comparator<Object> comparator = (Comparator<Object>) getPresentationContext()
							.getProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR);
					if (comparator != null) {
						Collections.sort(vmcs, comparator);
					}

					rm.setData(vmcs);
					rm.done();
				}
			});
		}
	}

	private final Map<TreePath, ContainerBreakpointsCache> fContainerBreakpointsCacheMap = new HashMap<>();

	private DataCache<IBreakpoint[]> fFilteredBreakpointsCache = new DataCache<IBreakpoint[]>(getExecutor()) {
		@Override
		protected void retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor<IBreakpoint[]> rm) {
			calcFileteredBreakpoints(rm);
		}
	};

	public BreakpointVMProvider(AbstractVMAdapter adapter, IPresentationContext context) {
		super(adapter, context);

		// Create the top level node which provides the anchor starting point.
		// This node is referenced by the BreakpointVMInput element so it
		// should not change when the view layout is updated.
		setRootNode(new RootDMVMNode(this));
		// Configure the rest of the layout nodes.
		configureLayout();

		context.addPropertyChangeListener(fPresentationContextListener);
		DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(fBreakpointsListener);
		IWorkbenchWindow window = context.getWindow();
		if (window != null) {
			DebugUITools.getDebugContextManager().getContextService(window)
					.addDebugContextListener(fDebugContextListener);
		}

	}

	@Override
	protected IVMModelProxy createModelProxyStrategy(Object rootElement) {
		return new BreakpointVMModelProxyStrategy(this, rootElement);
	}

	protected IVMNode createBreakpointVMNode() {
		return new BreakpointVMNode(this);
	}

	/**
	 * Configures the nodes of this provider.  This method may be over-ridden by
	 * sub classes to create an alternate configuration in this provider.
	 */
	protected void configureLayout() {
		IBreakpointOrganizer[] organizers = (IBreakpointOrganizer[]) getPresentationContext()
				.getProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS);

		IVMNode parentNode = getRootVMNode();
		if (organizers != null) {
			for (IBreakpointOrganizer organizer : organizers) {
				IVMNode organizerNode = new BreakpointOrganizerVMNode(this, organizer);
				addChildNodes(parentNode, new IVMNode[] { organizerNode });
				parentNode = organizerNode;
			}
		}

		IVMNode bpsNode = createBreakpointVMNode();
		addChildNodes(parentNode, new IVMNode[] { bpsNode });
	}

	@Override
	public void dispose() {
		getPresentationContext().removePropertyChangeListener(fPresentationContextListener);
		DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(fBreakpointsListener);
		IWorkbenchWindow window = getPresentationContext().getWindow();
		if (window != null) {
			DebugUITools.getDebugContextManager().getContextService(window)
					.removeDebugContextListener(fDebugContextListener);
		}
		super.dispose();
	}

	@Override
	public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
		return null;
	}

	@Override
	public String getColumnPresentationId(IPresentationContext context, Object element) {
		return null;
	}

	@Override
	public void update(IViewerInputUpdate update) {
		IDMContext activeDMContext = null;
		if (update.getElement() instanceof IDMVMContext) {
			activeDMContext = ((IDMVMContext) update.getElement()).getDMContext();
			activeDMContext = DMContexts.getAncestorOfType(activeDMContext, IBreakpointsTargetDMContext.class);
		}
		if (activeDMContext != null) {
			update.setInputElement(new BreakpointVMInput(getRootVMNode(), activeDMContext));
		} else {
			// If no breakpoints target found in active context, delegate the breakpoint
			// presentation to the default: breakpoint manager.
			update.setInputElement(new DefaultBreakpointsViewInput(update.getPresentationContext()));
		}
		update.done();
	}

	public void getNestingCategoryBreakpoints(TreePath path, final DataRequestMonitor<IBreakpoint[]> rm) {
		BreakpointOrganizerVMContext nestingOrganizerVmc = null;
		while (path.getSegmentCount() > 0) {
			if (path.getLastSegment() instanceof BreakpointOrganizerVMContext) {
				nestingOrganizerVmc = (BreakpointOrganizerVMContext) path.getLastSegment();
				break;
			}
			path = path.getParentPath();
		}
		if (nestingOrganizerVmc == null) {
			getFileteredBreakpoints(rm);
		} else {
			final BreakpointOrganizerVMContext _nestingOrganizerVmc = nestingOrganizerVmc;
			getBreakpointOrganizerVMCs((BreakpointOrganizerVMNode) _nestingOrganizerVmc.getVMNode(),
					path.getParentPath(),
					new DataRequestMonitor<List<BreakpointOrganizerVMContext>>(getExecutor(), rm) {
						@Override
						protected void handleSuccess() {
							int newVmcIdx = getData().indexOf(_nestingOrganizerVmc);

							if (newVmcIdx >= 0) {
								rm.setData(getData().get(newVmcIdx).getBreakpoints());
							} else {
								rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID,
										IDsfStatusConstants.INVALID_HANDLE, "Breakpoint category not found", null)); //$NON-NLS-1$
							}
							rm.done();
						}
					});
		}
	}

	public void getBreakpointOrganizerVMCs(BreakpointOrganizerVMNode organizerVMNode, TreePath path,
			DataRequestMonitor<List<BreakpointOrganizerVMContext>> rm) {
		ContainerBreakpointsCache cache = fContainerBreakpointsCacheMap.get(path);
		if (cache == null) {
			cache = new ContainerBreakpointsCache(organizerVMNode, path);
			fContainerBreakpointsCacheMap.put(path, cache);
		}

		cache.request(rm);
	}

	protected BreakpointOrganizerVMContext createBreakpointOrganizerVMContext(BreakpointOrganizerVMNode node,
			IAdaptable category, IBreakpoint[] breakpoints) {
		return new BreakpointOrganizerVMContext(node, category, breakpoints);
	}

	public void getFileteredBreakpoints(final DataRequestMonitor<IBreakpoint[]> rm) {
		fFilteredBreakpointsCache.request(rm);
	}

	protected void calcFileteredBreakpoints(DataRequestMonitor<IBreakpoint[]> rm) {
		rm.setData(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints());
		rm.done();
	}

	public void getBreakpointsForDebugContext(ISelection debugContext, DataRequestMonitor<IBreakpoint[]> rm) {
		rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED,
				"Not supported", null)); //$NON-NLS-1$
		rm.done();
	}

	public void handleEventInExecThread(final Object event) {
		getExecutor().execute(new DsfRunnable() {
			@Override
			public void run() {
				handleEvent(event);
			}
		});
	}

	@Override
	public void handleEvent(Object event, RequestMonitor rm) {
		if (isPresentationContextEvent(event)) {
			PropertyChangeEvent propertyEvent = (PropertyChangeEvent) event;
			if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) {
				clearNodes(false);
				configureLayout();
			}
		}
		super.handleEvent(event, rm);
	}

	public static boolean isPresentationContextEvent(Object event) {
		return event instanceof PropertyChangeEvent
				&& ((PropertyChangeEvent) event).getSource() instanceof IPresentationContext;
	}

	public static boolean isBreakpointOrganizerEvent(Object event) {
		return event instanceof PropertyChangeEvent
				&& ((PropertyChangeEvent) event).getSource() instanceof IBreakpointOrganizerDelegate;
	}

	private static final int MODEL_DELTA_CHANGE_FLAGS = IModelDelta.STATE | IModelDelta.CONTENT | IModelDelta.ADDED
			| IModelDelta.REMOVED | IModelDelta.REPLACED | IModelDelta.INSERTED;

	@Override
	protected void handleEvent(IVMModelProxy proxyStrategy, Object event, RequestMonitor rm) {
		// Before generating a delta, flush the caches.
		int deltaFlags = proxyStrategy.getEventDeltaFlags(event);
		if ((deltaFlags & MODEL_DELTA_CHANGE_FLAGS) != 0) {
			flushCaches();
		}

		super.handleEvent(proxyStrategy, event, rm);
	}

	private void flushCaches() {
		fFilteredBreakpointsCache.reset();
		for (DataCache<?> cache : fContainerBreakpointsCacheMap.values()) {
			cache.reset();
		}
		fContainerBreakpointsCacheMap.clear();
	}
}

Back to the top