1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.debug.ui.actions;
15 
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.List;
19 
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.model.IBreakpoint;
23 import org.eclipse.debug.core.model.IValue;
24 import org.eclipse.debug.internal.ui.AbstractDebugCheckboxSelectionDialog;
25 import org.eclipse.debug.ui.DebugUITools;
26 import org.eclipse.debug.ui.IDebugModelPresentation;
27 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
28 import org.eclipse.jdt.debug.core.IJavaClassType;
29 import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint;
30 import org.eclipse.jdt.debug.core.IJavaFieldVariable;
31 import org.eclipse.jdt.debug.core.IJavaObject;
32 import org.eclipse.jdt.debug.core.IJavaType;
33 import org.eclipse.jdt.debug.core.IJavaVariable;
34 import org.eclipse.jdt.debug.core.IJavaWatchpoint;
35 import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
36 import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds;
37 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
38 import org.eclipse.jface.action.IAction;
39 import org.eclipse.jface.dialogs.MessageDialog;
40 import org.eclipse.jface.viewers.IBaseLabelProvider;
41 import org.eclipse.jface.viewers.IStructuredSelection;
42 import org.eclipse.jface.window.Window;
43 import org.eclipse.osgi.util.NLS;
44 import org.eclipse.swt.SWT;
45 import org.eclipse.swt.widgets.Shell;
46 
47 /**
48  * Action to associate an object with one or more breakpoints.
49  */
50 public class InstanceFiltersAction extends ObjectActionDelegate {
51 
52 	/**
53 	 * Dialog that allows the user to select one or more breakpoints that should be restricted
54 	 * to a specific object instance.
55 	 */
56 	class InstanceFilterDialog extends AbstractDebugCheckboxSelectionDialog {
57 
58 		private Object fInput;
59 		private String fMessage;
60 		private IBaseLabelProvider fLabelProvider;
61 
InstanceFilterDialog(Shell parentShell, Object input, IBaseLabelProvider labelProvider, String message)62 		public InstanceFilterDialog(Shell parentShell, Object input, IBaseLabelProvider labelProvider, String message){
63 			super(parentShell);
64 			fInput = input;
65 			fMessage = message;
66 			fLabelProvider = labelProvider;
67 			setShellStyle(getShellStyle() | SWT.RESIZE);
68 			setShowSelectAllButtons(true);
69 		}
70 
71 		/* (non-Javadoc)
72 		 * @see org.eclipse.debug.internal.ui.AbstractDebugCheckboxSelectionDialog#isValid()
73 		 */
74 		@Override
isValid()75 		protected boolean isValid() {
76 			return true;
77 		}
78 
79 		/* (non-Javadoc)
80 		 * @see org.eclipse.debug.internal.ui.launchConfigurations.AbstractDebugSelectionDialog#getDialogSettingsId()
81 		 */
82 		@Override
getDialogSettingsId()83 		protected String getDialogSettingsId() {
84 			return IJavaDebugUIConstants.PLUGIN_ID + ".INSTANCE_FILTERS_ACTION_DIALOG"; //$NON-NLS-1$
85 		}
86 
87 		/* (non-Javadoc)
88 		 * @see org.eclipse.debug.internal.ui.launchConfigurations.AbstractDebugSelectionDialog#getHelpContextId()
89 		 */
90 		@Override
getHelpContextId()91 		protected String getHelpContextId() {
92 			return IJavaDebugHelpContextIds.INSTANCE_BREAKPOINT_SELECTION_DIALOG;
93 		}
94 
95 		/* (non-Javadoc)
96 		 * @see org.eclipse.debug.internal.ui.launchConfigurations.AbstractDebugSelectionDialog#getViewerInput()
97 		 */
98 		@Override
getViewerInput()99 		protected Object getViewerInput() {
100 			return fInput;
101 		}
102 
103 		/* (non-Javadoc)
104 		 * @see org.eclipse.debug.internal.ui.launchConfigurations.AbstractDebugSelectionDialog#getViewerLabel()
105 		 */
106 		@Override
getViewerLabel()107 		protected String getViewerLabel() {
108 			return fMessage;
109 		}
110 
111 		/* (non-Javadoc)
112 		 * @see org.eclipse.debug.internal.ui.launchConfigurations.AbstractDebugSelectionDialog#getLabelProvider()
113 		 */
114 		@Override
getLabelProvider()115 		protected IBaseLabelProvider getLabelProvider() {
116 			return fLabelProvider;
117 		}
118 }
119 
120 	/**
121 	 * @see org.eclipse.ui.IActionDelegate#run(IAction)
122 	 */
123 	@Override
run(IAction action)124 	public void run(IAction action) {
125 		IStructuredSelection selection = getCurrentSelection();
126 		if (selection == null || selection.size() > 1) {
127 			return;
128 		}
129 
130 		Object o = selection.getFirstElement();
131 		if (o instanceof IJavaVariable) {
132 			final IJavaVariable var = (IJavaVariable)o;
133 			try {
134 				IValue value = var.getValue();
135 				if (value instanceof IJavaObject) {
136 					final IJavaObject object = (IJavaObject)value;
137 					final List<IJavaBreakpoint> breakpoints = getApplicableBreakpoints(var, object);
138 					final IDebugModelPresentation modelPresentation= DebugUITools.newDebugModelPresentation();
139 
140 					if (breakpoints.isEmpty())
141 					{
142 						MessageDialog.openInformation(JDIDebugUIPlugin.getActiveWorkbenchShell(), ActionMessages.InstanceFiltersAction_0, ActionMessages.InstanceFiltersAction_4);
143 						return;
144 					}
145 
146 					InstanceFilterDialog dialog = new InstanceFilterDialog(JDIDebugUIPlugin.getActiveWorkbenchShell(), breakpoints, modelPresentation, NLS.bind(ActionMessages.InstanceFiltersAction_1, new String[] {var.getName()})){
147 						@Override
148 						public void okPressed() {
149 							// check if breakpoints have already been restricted to other objects.
150 							Object[] checkBreakpoint= getCheckBoxTableViewer().getCheckedElements();
151 							for (int k= 0; k < checkBreakpoint.length; k++) {
152 								IJavaBreakpoint breakpoint= (IJavaBreakpoint) checkBreakpoint[k];
153 								try {
154 									IJavaObject[] instanceFilters= breakpoint.getInstanceFilters();
155 									boolean sameTarget = false;
156 									for (int i = 0; i < instanceFilters.length; i++) {
157 										IJavaObject instanceFilter = instanceFilters[i];
158 										if (instanceFilter.getDebugTarget().equals(object.getDebugTarget())) {
159 											sameTarget = true;
160 											break;
161 										}
162 									}
163 									if (sameTarget) {
164 										MessageDialog messageDialog= new MessageDialog(JDIDebugUIPlugin.getActiveWorkbenchShell(), ActionMessages.InstanceFiltersAction_2,
165 											null, NLS.bind(ActionMessages.InstanceFiltersAction_3, new String[] { modelPresentation.getText(breakpoint), var.getName()}),
166 											MessageDialog.QUESTION, new String[] { ActionMessages.InstanceFiltersAction_Yes_2, ActionMessages.InstanceFiltersAction_Cancel_3}, //
167 											0);
168 										if (messageDialog.open() == Window.OK) {
169 											for (int i= 0; i < instanceFilters.length; i++) {
170 												breakpoint.removeInstanceFilter(instanceFilters[i]);
171 											}
172 										} else {
173 											// if 'cancel', do not close the instance filter dialog
174 											return;
175 										}
176 									}
177 								} catch (CoreException e) {
178 									JDIDebugUIPlugin.log(e);
179 								}
180 							}
181 							super.okPressed();
182 						}
183 					};
184 					dialog.setTitle(ActionMessages.InstanceFiltersAction_2);
185 
186 					// determine initial selection
187 					List<IJavaBreakpoint> existing = new ArrayList<>();
188 					Iterator<IJavaBreakpoint> iter = breakpoints.iterator();
189 					while (iter.hasNext()) {
190 						IJavaBreakpoint bp = iter.next();
191 						IJavaObject[] filters = bp.getInstanceFilters();
192 						for (int i = 0; i < filters.length; i++) {
193 							if (filters[i].equals(object)) {
194 								existing.add(bp);
195 								break;
196 							}
197 						}
198 					}
199 					dialog.setInitialSelections(existing.toArray());
200 
201 					if (dialog.open() == Window.OK) {
202 						Object[] selectedBreakpoints = dialog.getResult();
203 						if (selectedBreakpoints != null) {
204 							// add
205 							for (int i = 0; i < selectedBreakpoints.length; i++) {
206 								IJavaBreakpoint bp = (IJavaBreakpoint)selectedBreakpoints[i];
207 								bp.addInstanceFilter(object);
208 								existing.remove(bp);
209 							}
210 							// remove
211 							iter = existing.iterator();
212 							while (iter.hasNext()) {
213 								IJavaBreakpoint bp = iter.next();
214 								bp.removeInstanceFilter(object);
215 							}
216 						}
217 					}
218 				} else {
219 					// only allowed for objects
220 				}
221 			} catch (CoreException e) {
222 				JDIDebugUIPlugin.log(e);
223 			}
224 		}
225 	}
226 
getApplicableBreakpoints(IJavaVariable variable, IJavaObject object)227 	protected List<IJavaBreakpoint> getApplicableBreakpoints(IJavaVariable variable, IJavaObject object) {
228 		List<IJavaBreakpoint> breakpoints = new ArrayList<>();
229 
230 		try {
231 			// collect names in type hierarchy
232 			List<String> superTypeNames = new ArrayList<>();
233 			IJavaType type = object.getJavaType();
234 			while (type instanceof IJavaClassType) {
235 				superTypeNames.add(type.getName());
236 				type = ((IJavaClassType)type).getSuperclass();
237 			}
238 
239 			IBreakpoint[] allBreakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
240 			for (int i = 0; i < allBreakpoints.length; i++) {
241 				if (allBreakpoints[i] instanceof IJavaBreakpoint) {
242 					IJavaBreakpoint jbp = (IJavaBreakpoint)allBreakpoints[i];
243 					IJavaBreakpoint valid = null;
244 					if (jbp instanceof IJavaWatchpoint && variable instanceof IJavaFieldVariable) {
245 						IJavaWatchpoint wp = (IJavaWatchpoint)jbp;
246 						IJavaFieldVariable fv = (IJavaFieldVariable)variable;
247 						if (variable.getName().equals(wp.getFieldName()) && fv.getDeclaringType().getName().equals(wp.getTypeName())) {
248 							valid = wp;
249 						}
250 					} else if (superTypeNames.contains(jbp.getTypeName()) || jbp instanceof IJavaExceptionBreakpoint) {
251 						valid = jbp;
252 					}
253 					if (valid != null && valid.supportsInstanceFilters()) {
254 						breakpoints.add(valid);
255 					}
256 				}
257 			}
258 		} catch (CoreException e) {
259 			JDIDebugUIPlugin.log(e);
260 		}
261 
262 		return breakpoints;
263 	}
264 
265 }
266