1 13 14 package org.eclipse.jdt.ui.actions; 15 16 import com.ibm.icu.text.Collator; 17 18 import java.lang.reflect.InvocationTargetException ; 19 import java.util.ArrayList ; 20 import java.util.HashSet ; 21 import java.util.List ; 22 import java.util.Set ; 23 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IStatus; 26 27 import org.eclipse.swt.SWT; 28 import org.eclipse.swt.events.SelectionAdapter; 29 import org.eclipse.swt.events.SelectionEvent; 30 import org.eclipse.swt.graphics.Image; 31 import org.eclipse.swt.layout.GridData; 32 import org.eclipse.swt.widgets.Composite; 33 import org.eclipse.swt.widgets.Control; 34 import org.eclipse.swt.widgets.Link; 35 import org.eclipse.swt.widgets.Shell; 36 37 import org.eclipse.jface.dialogs.MessageDialog; 38 import org.eclipse.jface.operation.IRunnableContext; 39 import org.eclipse.jface.viewers.ILabelProvider; 40 import org.eclipse.jface.viewers.IStructuredSelection; 41 import org.eclipse.jface.viewers.ITreeContentProvider; 42 import org.eclipse.jface.viewers.Viewer; 43 import org.eclipse.jface.viewers.ViewerComparator; 44 import org.eclipse.jface.window.Window; 45 46 import org.eclipse.jface.text.IRewriteTarget; 47 import org.eclipse.jface.text.ITextSelection; 48 49 import org.eclipse.ui.IEditorPart; 50 import org.eclipse.ui.IWorkbenchSite; 51 import org.eclipse.ui.PlatformUI; 52 import org.eclipse.ui.dialogs.ISelectionStatusValidator; 53 54 import org.eclipse.jdt.core.ICompilationUnit; 55 import org.eclipse.jdt.core.IField; 56 import org.eclipse.jdt.core.IJavaElement; 57 import org.eclipse.jdt.core.IType; 58 import org.eclipse.jdt.core.JavaModelException; 59 import org.eclipse.jdt.core.Signature; 60 import org.eclipse.jdt.core.dom.AST; 61 import org.eclipse.jdt.core.dom.CompilationUnit; 62 import org.eclipse.jdt.core.dom.IBinding; 63 import org.eclipse.jdt.core.dom.IMethodBinding; 64 import org.eclipse.jdt.core.dom.ITypeBinding; 65 import org.eclipse.jdt.core.dom.IVariableBinding; 66 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 67 68 import org.eclipse.jdt.internal.corext.codemanipulation.AddDelegateMethodsOperation; 69 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; 70 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2; 71 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 72 import org.eclipse.jdt.internal.corext.dom.Bindings; 73 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; 74 import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; 75 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 76 import org.eclipse.jdt.internal.corext.template.java.CodeTemplateContextType; 77 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 78 import org.eclipse.jdt.internal.corext.util.JdtFlags; 79 import org.eclipse.jdt.internal.corext.util.Messages; 80 81 import org.eclipse.jdt.ui.JavaUI; 82 83 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; 84 import org.eclipse.jdt.internal.ui.JavaPlugin; 85 import org.eclipse.jdt.internal.ui.actions.ActionMessages; 86 import org.eclipse.jdt.internal.ui.actions.ActionUtil; 87 import org.eclipse.jdt.internal.ui.actions.SelectionConverter; 88 import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter; 89 import org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog; 90 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; 91 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; 92 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; 93 import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext; 94 import org.eclipse.jdt.internal.ui.util.ElementValidator; 95 import org.eclipse.jdt.internal.ui.util.ExceptionHandler; 96 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 97 98 115 public class AddDelegateMethodsAction extends SelectionDispatchAction { 116 117 119 private static class AddDelegateMethodsActionStatusValidator implements ISelectionStatusValidator { 120 121 private static int fEntries; 122 123 AddDelegateMethodsActionStatusValidator(int entries) { 124 fEntries= entries; 125 } 126 127 public IStatus validate(Object [] selection) { 128 StatusInfo info= new StatusInfo(); 129 if (selection != null && selection.length > 0) { 130 int count= 0; 131 List bindings= new ArrayList (selection.length); 132 IMethodBinding binding= null; 133 for (int index= 0; index < selection.length; index++) { 134 if (selection[index] instanceof IBinding[]) { 135 count++; 136 binding= (IMethodBinding) ((IBinding[]) selection[index])[1]; 137 IMethodBinding existing= null; 138 for (int offset= 0; offset < bindings.size(); offset++) { 139 existing= (IMethodBinding) bindings.get(offset); 140 if (Bindings.isEqualMethod(binding, existing.getName(), existing.getParameterTypes())) { 141 return new StatusInfo(IStatus.ERROR, ActionMessages.AddDelegateMethodsAction_duplicate_methods); 142 } 143 } 144 bindings.add(binding); 145 info= new StatusInfo(IStatus.INFO, Messages.format(ActionMessages.AddDelegateMethodsAction_selectioninfo_more, new Object [] { String.valueOf(count), String.valueOf(fEntries)})); 146 } 147 } 148 } 149 return info; 150 } 151 } 152 153 private static class AddDelegateMethodsContentProvider implements ITreeContentProvider { 154 155 private IBinding[][] fBindings= new IBinding[0][0]; 156 157 private int fCount= 0; 158 159 private IVariableBinding[] fExpanded= new IVariableBinding[0]; 160 161 private final CompilationUnit fUnit; 162 163 AddDelegateMethodsContentProvider(IType type, IField[] fields) throws JavaModelException { 164 RefactoringASTParser parser= new RefactoringASTParser(AST.JLS3); 165 fUnit= parser.parse(type.getCompilationUnit(), true); 166 final ITypeBinding binding= ASTNodes.getTypeBinding(fUnit, type); 167 if (binding != null) { 168 IBinding[][] bindings= StubUtility2.getDelegatableMethods(fUnit.getAST(), binding); 169 if (bindings != null) { 170 fBindings= bindings; 171 fCount= bindings.length; 172 } 173 List expanded= new ArrayList (); 174 for (int index= 0; index < fields.length; index++) { 175 VariableDeclarationFragment fragment= ASTNodeSearchUtil.getFieldDeclarationFragmentNode(fields[index], fUnit); 176 if (fragment != null) { 177 IVariableBinding variableBinding= fragment.resolveBinding(); 178 if (variableBinding != null) 179 expanded.add(variableBinding); 180 } 181 } 182 IVariableBinding[] result= new IVariableBinding[expanded.size()]; 183 expanded.toArray(result); 184 fExpanded= result; 185 } 186 } 187 188 public CompilationUnit getCompilationUnit() { 189 return fUnit; 190 } 191 192 public void dispose() { 193 } 194 195 public Object [] getChildren(Object element) { 196 if (element instanceof IVariableBinding) { 197 IVariableBinding binding= (IVariableBinding) element; 198 List result= new ArrayList (); 199 final String key= binding.getKey(); 200 for (int index= 0; index < fBindings.length; index++) 201 if (fBindings[index][0].getKey().equals(key)) 202 result.add(fBindings[index]); 203 return result.toArray(); 204 } 205 return null; 206 } 207 208 public int getCount() { 209 return fCount; 210 } 211 212 public Object [] getElements(Object inputElement) { 213 Set keys= new HashSet (); 214 List result= new ArrayList (); 215 for (int index= 0; index < fBindings.length; index++) { 216 IBinding[] bindings= fBindings[index]; 217 final String key= bindings[0].getKey(); 218 if (!keys.contains(key)) { 219 keys.add(key); 220 result.add(bindings[0]); 221 } 222 } 223 return result.toArray(); 224 } 225 226 public IVariableBinding[] getExpandedElements() { 227 return fExpanded; 228 } 229 230 public IBinding[][] getInitiallySelectedElements() { 231 List result= new ArrayList (); 232 for (int index= 0; index < fBindings.length; index++) 233 for (int offset= 0; offset < fExpanded.length; offset++) 234 if (fExpanded[offset].getKey().equals(fBindings[index][0].getKey())) 235 result.add(fBindings[index]); 236 return (IBinding[][]) result.toArray(new IBinding[result.size()][2]); 237 } 238 239 public Object getParent(Object element) { 240 if (element instanceof IBinding[]) 241 return ((IBinding[]) element)[0]; 242 return null; 243 } 244 245 public boolean hasChildren(Object element) { 246 return element instanceof IVariableBinding; 247 } 248 249 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { 250 } 251 } 252 253 private static class AddDelegateMethodsDialog extends SourceActionDialog { 254 255 public AddDelegateMethodsDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider, CompilationUnitEditor editor, IType type, boolean isConstructor) throws JavaModelException { 256 super(parent, labelProvider, contentProvider, editor, type, isConstructor); 257 } 258 259 protected void configureShell(Shell shell) { 260 super.configureShell(shell); 261 PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IJavaHelpContextIds.ADD_DELEGATE_METHODS_SELECTION_DIALOG); 262 } 263 264 267 protected Control createLinkControl(Composite composite) { 268 Link link= new Link(composite, SWT.WRAP); 269 link.setText(ActionMessages.AddDelegateMethodsAction_template_link_message); 270 link.addSelectionListener(new SelectionAdapter() { 271 public void widgetSelected(SelectionEvent e) { 272 openCodeTempatePage(CodeTemplateContextType.OVERRIDECOMMENT_ID); 273 } 274 }); 275 link.setToolTipText(ActionMessages.AddDelegateMethodsAction_template_link_tooltip); 276 277 GridData gridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false); 278 gridData.widthHint= convertWidthInCharsToPixels(40); link.setLayoutData(gridData); 280 return link; 281 } 282 } 283 284 private static class AddDelegateMethodsLabelProvider extends BindingLabelProvider { 285 286 public Image getImage(Object element) { 287 if (element instanceof IBinding[]) { 288 return super.getImage((((IBinding[]) element)[1])); 289 } else if (element instanceof IVariableBinding) { 290 return super.getImage(element); 291 } 292 return null; 293 } 294 295 public String getText(Object element) { 296 if (element instanceof IBinding[]) { 297 return super.getText((((IBinding[]) element)[1])); 298 } else if (element instanceof IVariableBinding) { 299 return super.getText(element); 300 } 301 return null; 302 } 303 } 304 305 private static class AddDelegateMethodsViewerComparator extends ViewerComparator { 306 307 private final BindingLabelProvider fProvider= new BindingLabelProvider(); 308 private final Collator fCollator= Collator.getInstance(); 309 310 public int category(Object element) { 311 if (element instanceof IBinding[]) 312 return 0; 313 return 1; 314 } 315 316 public int compare(Viewer viewer, Object object1, Object object2) { 317 String first= ""; String second= ""; if (object1 instanceof IBinding[]) 320 first= fProvider.getText(((IBinding[]) object1)[1]); 321 else if (object1 instanceof IVariableBinding) 322 first= ((IBinding) object1).getName(); 323 if (object2 instanceof IBinding[]) 324 second= fProvider.getText(((IBinding[]) object2)[1]); 325 else if (object2 instanceof IVariableBinding) 326 second= ((IBinding) object2).getName(); 327 return fCollator.compare(first, second); 328 } 329 } 330 331 private static final String DIALOG_TITLE= ActionMessages.AddDelegateMethodsAction_error_title; 332 333 private static boolean hasPrimitiveType(IField field) throws JavaModelException { 334 String signature= field.getTypeSignature(); 335 char first= Signature.getElementType(signature).charAt(0); 336 return (first != Signature.C_RESOLVED && first != Signature.C_UNRESOLVED); 337 } 338 339 private static boolean isArray(IField field) throws JavaModelException { 340 return Signature.getArrayCount(field.getTypeSignature()) > 0; 341 } 342 343 private CompilationUnitEditor fEditor; 344 345 351 public AddDelegateMethodsAction(CompilationUnitEditor editor) { 352 this(editor.getEditorSite()); 353 fEditor= editor; 354 setEnabled(SelectionConverter.getInputAsCompilationUnit(editor) != null); 355 } 356 357 364 public AddDelegateMethodsAction(IWorkbenchSite site) { 365 super(site); 366 setText(ActionMessages.AddDelegateMethodsAction_label); 367 setDescription(ActionMessages.AddDelegateMethodsAction_description); 368 setToolTipText(ActionMessages.AddDelegateMethodsAction_tooltip); 369 370 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.ADD_DELEGATE_METHODS_ACTION); 371 } 372 373 private boolean canEnable(IStructuredSelection selection) throws JavaModelException { 374 if (getSelectedFields(selection) != null) 375 return true; 376 377 if ((selection.size() == 1) && (selection.getFirstElement() instanceof IType)) { 378 IType type= (IType) selection.getFirstElement(); 379 return type.getCompilationUnit() != null && !type.isInterface(); 380 } 381 382 if ((selection.size() == 1) && (selection.getFirstElement() instanceof ICompilationUnit)) 383 return true; 384 385 return false; 386 } 387 388 private boolean canRunOn(IField[] fields) throws JavaModelException { 389 if (fields == null || fields.length == 0) 390 return false; 391 int count= 0; 392 for (int index= 0; index < fields.length; index++) { 393 if (!JdtFlags.isEnum(fields[index]) && !hasPrimitiveType(fields[index]) || isArray(fields[index])) 394 count++; 395 } 396 if (count == 0) 397 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_not_applicable); 398 return (count > 0); 399 } 400 401 private boolean canRunOn(IType type) throws JavaModelException { 402 if (type == null || type.getCompilationUnit() == null) { 403 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_not_in_source_file); 404 return false; 405 } else if (type.isAnnotation()) { 406 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_annotation_not_applicable); 407 return false; 408 } else if (type.isInterface()) { 409 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_interface_not_applicable); 410 return false; 411 } 412 return canRunOn(type.getFields()); 413 } 414 415 private IField[] getSelectedFields(IStructuredSelection selection) { 416 List elements= selection.toList(); 417 if (elements.size() > 0) { 418 IField[] result= new IField[elements.size()]; 419 ICompilationUnit unit= null; 420 for (int index= 0; index < elements.size(); index++) { 421 if (elements.get(index) instanceof IField) { 422 IField field= (IField) elements.get(index); 423 424 if (index == 0) { 425 unit= field.getCompilationUnit(); 427 if (unit == null) { 428 return null; 429 } 430 } else if (!unit.equals(field.getCompilationUnit())) { 431 return null; 433 } 434 try { 435 final IType type= field.getDeclaringType(); 436 if (type.isInterface()) { 437 return null; 438 } 439 } catch (JavaModelException exception) { 440 JavaPlugin.log(exception); 441 return null; 442 } 443 444 result[index]= field; 445 } else { 446 return null; 447 } 448 } 449 return result; 450 } 451 return null; 452 } 453 454 457 public void run(IStructuredSelection selection) { 458 try { 459 IField[] selectedFields= getSelectedFields(selection); 460 if (canRunOn(selectedFields)) { 461 run(selectedFields[0].getDeclaringType(), selectedFields, false); 462 return; 463 } 464 Object firstElement= selection.getFirstElement(); 465 if (firstElement instanceof IType) 466 run((IType) firstElement, new IField[0], false); 467 else if (firstElement instanceof ICompilationUnit) 468 run(JavaElementUtil.getMainType((ICompilationUnit) firstElement), new IField[0], false); 469 else if (!(firstElement instanceof IField)) 470 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_not_applicable); 471 } catch (CoreException e) { 472 ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_error_actionfailed); 473 } 474 475 } 476 477 480 public void run(ITextSelection selection) { 481 try { 482 if (!ActionUtil.isProcessable(fEditor)) 483 return; 484 485 IJavaElement[] elements= SelectionConverter.codeResolveForked(fEditor, true); 486 if (elements.length == 1 && (elements[0] instanceof IField)) { 487 IField field= (IField) elements[0]; 488 run(field.getDeclaringType(), new IField[] { field}, true); 489 return; 490 } 491 IJavaElement element= SelectionConverter.getElementAtOffset(fEditor); 492 if (element != null) { 493 IType type= (IType) element.getAncestor(IJavaElement.TYPE); 494 if (type != null) { 495 if (type.getFields().length > 0) { 496 run(type, new IField[0], true); 497 return; 498 } 499 } 500 } 501 MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_not_applicable); 502 } catch (CoreException e) { 503 ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_error_actionfailed); 504 } catch (InvocationTargetException e) { 505 ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_error_actionfailed); 506 } catch (InterruptedException e) { 507 } 509 } 510 511 private void run(IType type, IField[] preselected, boolean editor) throws CoreException { 512 if (!ElementValidator.check(type, getShell(), DIALOG_TITLE, editor)) 513 return; 514 if (!ActionUtil.isEditable(fEditor, getShell(), type)) 515 return; 516 if (!canRunOn(type)) 517 return; 518 showUI(type, preselected); 519 } 520 521 523 526 public void selectionChanged(IStructuredSelection selection) { 527 try { 528 setEnabled(canEnable(selection)); 529 } catch (JavaModelException e) { 530 if (JavaModelUtil.isExceptionToBeLogged(e)) 532 JavaPlugin.log(e); 533 setEnabled(false); 534 } 535 } 536 537 539 542 public void selectionChanged(ITextSelection selection) { 543 } 544 545 private void showUI(IType type, IField[] fields) { 546 try { 547 AddDelegateMethodsContentProvider provider= new AddDelegateMethodsContentProvider(type, fields); 548 SourceActionDialog dialog= new AddDelegateMethodsDialog(getShell(), new AddDelegateMethodsLabelProvider(), provider, fEditor, type, false); 549 dialog.setValidator(new AddDelegateMethodsActionStatusValidator(provider.getCount())); 550 AddDelegateMethodsViewerComparator comparator= new AddDelegateMethodsViewerComparator(); 551 dialog.setComparator(comparator); 552 dialog.setInput(new Object ()); 553 dialog.setContainerMode(true); 554 dialog.setMessage(ActionMessages.AddDelegateMethodsAction_message); 555 dialog.setTitle(ActionMessages.AddDelegateMethodsAction_title); 556 IVariableBinding[] expanded= provider.getExpandedElements(); 557 if (expanded.length > 0) { 558 dialog.setExpandedElements(expanded); 559 } else { 560 Object [] elements= provider.getElements(null); 561 if (elements.length > 0) { 562 comparator.sort(null, elements); 563 Object [] expand= { elements[0]}; 564 dialog.setExpandedElements(expand); 565 } 566 } 567 dialog.setInitialSelections(provider.getInitiallySelectedElements()); 568 dialog.setSize(60, 18); 569 int result= dialog.open(); 570 if (result == Window.OK) { 571 Object [] object= dialog.getResult(); 572 if (object == null) { 573 notifyResult(false); 574 return; 575 } 576 List tuples= new ArrayList (object.length); 577 for (int index= 0; index < object.length; index++) { 578 if (object[index] instanceof IBinding[]) 579 tuples.add(object[index]); 580 } 581 IEditorPart part= JavaUI.openInEditor(type); 582 IRewriteTarget target= (IRewriteTarget) part.getAdapter(IRewriteTarget.class); 583 try { 584 if (target != null) 585 target.beginCompoundChange(); 586 CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(type.getJavaProject()); 587 settings.createComments= dialog.getGenerateComment(); 588 final int size= tuples.size(); 589 String [] methodKeys= new String [size]; 590 String [] variableKeys= new String [size]; 591 for (int index= 0; index < size; index++) { 592 final IBinding[] tuple= (IBinding[]) tuples.get(index); 593 variableKeys[index]= tuple[0].getKey(); 594 methodKeys[index]= tuple[1].getKey(); 595 } 596 AddDelegateMethodsOperation operation= new AddDelegateMethodsOperation(type, dialog.getElementPosition(), provider.getCompilationUnit(), variableKeys, methodKeys, settings, true, false); 597 IRunnableContext context= JavaPlugin.getActiveWorkbenchWindow(); 598 if (context == null) 599 context= new BusyIndicatorRunnableContext(); 600 try { 601 PlatformUI.getWorkbench().getProgressService().runInUI(context, new WorkbenchRunnableAdapter(operation, operation.getSchedulingRule()), operation.getSchedulingRule()); 602 } catch (InterruptedException exception) { 603 } 605 } finally { 606 if (target != null) 607 target.endCompoundChange(); 608 } 609 } 610 notifyResult(result == Window.OK); 611 } catch (CoreException exception) { 612 ExceptionHandler.handle(exception, DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_error_actionfailed); 613 } catch (InvocationTargetException e) { 614 ExceptionHandler.handle(e, DIALOG_TITLE, ActionMessages.AddDelegateMethodsAction_error_actionfailed); 615 } 616 } 617 } 618 | Popular Tags |