1 11 package org.eclipse.jdt.internal.ui.refactoring; 12 13 import java.lang.reflect.InvocationTargetException ; 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.IProgressMonitor; 25 import org.eclipse.core.runtime.SubProgressMonitor; 26 27 import org.eclipse.swt.SWT; 28 import org.eclipse.swt.custom.SashForm; 29 import org.eclipse.swt.events.SelectionAdapter; 30 import org.eclipse.swt.events.SelectionEvent; 31 import org.eclipse.swt.layout.GridData; 32 import org.eclipse.swt.layout.GridLayout; 33 import org.eclipse.swt.widgets.Button; 34 import org.eclipse.swt.widgets.Composite; 35 import org.eclipse.swt.widgets.Label; 36 import org.eclipse.swt.widgets.Tree; 37 38 import org.eclipse.jface.dialogs.Dialog; 39 import org.eclipse.jface.operation.IRunnableWithProgress; 40 import org.eclipse.jface.preference.IPreferenceStore; 41 import org.eclipse.jface.resource.JFaceResources; 42 import org.eclipse.jface.viewers.CheckStateChangedEvent; 43 import org.eclipse.jface.viewers.ICheckStateListener; 44 import org.eclipse.jface.viewers.ISelection; 45 import org.eclipse.jface.viewers.ISelectionChangedListener; 46 import org.eclipse.jface.viewers.IStructuredSelection; 47 import org.eclipse.jface.viewers.ITreeContentProvider; 48 import org.eclipse.jface.viewers.SelectionChangedEvent; 49 import org.eclipse.jface.viewers.Viewer; 50 import org.eclipse.jface.viewers.ViewerFilter; 51 import org.eclipse.jface.wizard.IWizardPage; 52 53 import org.eclipse.jface.text.Document; 54 import org.eclipse.jface.text.IDocument; 55 import org.eclipse.jface.text.source.SourceViewer; 56 57 import org.eclipse.ui.PlatformUI; 58 import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer; 59 60 import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; 61 62 import org.eclipse.jdt.core.IJavaProject; 63 import org.eclipse.jdt.core.IMember; 64 import org.eclipse.jdt.core.IMethod; 65 import org.eclipse.jdt.core.ISourceReference; 66 import org.eclipse.jdt.core.IType; 67 import org.eclipse.jdt.core.ITypeHierarchy; 68 import org.eclipse.jdt.core.JavaModelException; 69 70 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 71 import org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor; 72 import org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoring; 73 import org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor; 74 import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; 75 import org.eclipse.jdt.internal.corext.util.Messages; 76 import org.eclipse.jdt.internal.corext.util.Strings; 77 78 import org.eclipse.jdt.ui.JavaElementComparator; 79 import org.eclipse.jdt.ui.JavaElementLabelProvider; 80 import org.eclipse.jdt.ui.PreferenceConstants; 81 import org.eclipse.jdt.ui.text.JavaSourceViewerConfiguration; 82 83 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; 84 import org.eclipse.jdt.internal.ui.JavaPlugin; 85 import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer; 86 import org.eclipse.jdt.internal.ui.util.ExceptionHandler; 87 import org.eclipse.jdt.internal.ui.util.SWTUtil; 88 89 95 public class PullUpMethodPage extends UserInputWizardPage { 96 97 private static class PullUpFilter extends ViewerFilter { 98 99 private static boolean anySubtypeCanBeShown(final IType type, final Map typeToMemberArray, final ITypeHierarchy hierarchy) { 100 final IType[] subTypes= hierarchy.getSubtypes(type); 101 for (int i= 0; i < subTypes.length; i++) { 102 if (canBeShown(subTypes[i], typeToMemberArray, hierarchy)) 103 return true; 104 } 105 return false; 106 } 107 108 private static boolean canBeShown(final IType type, final Map typeToMemberArray, final ITypeHierarchy hierarchy) { 109 if (typeToMemberArray.containsKey(type)) 110 return true; 111 return anySubtypeCanBeShown(type, typeToMemberArray, hierarchy); 112 } 113 114 private static Set computeShowableSubtypesOfMainType(final ITypeHierarchy hierarchy, final Map typeToMemberArray) { 115 final Set result= new HashSet (); 116 final IType[] subtypes= hierarchy.getAllSubtypes(hierarchy.getType()); 117 for (int i= 0; i < subtypes.length; i++) { 118 final IType subtype= subtypes[i]; 119 if (canBeShown(subtype, typeToMemberArray, hierarchy)) 120 result.add(subtype); 121 } 122 return result; 123 } 124 125 private static Set computeTypesToShow(final ITypeHierarchy hierarchy, final Map typeToMemberArray) { 126 final Set typesToShow= new HashSet (); 127 typesToShow.add(hierarchy.getType()); 128 typesToShow.addAll(computeShowableSubtypesOfMainType(hierarchy, typeToMemberArray)); 129 return typesToShow; 130 } 131 132 private final Set fTypesToShow; 133 134 public PullUpFilter(final ITypeHierarchy hierarchy, final IMember[] members) { 135 final Map map= PullUpMethodPage.createTypeToMemberArrayMapping(members); 137 fTypesToShow= computeTypesToShow(hierarchy, map); 138 } 139 140 public boolean select(final Viewer viewer, final Object parentElement, final Object element) { 141 if (element instanceof IMethod) 142 return true; 143 return fTypesToShow.contains(element); 144 } 145 } 146 147 private static class PullUpHierarchyContentProvider implements ITreeContentProvider { 148 149 private IType fDeclaringType; 150 151 private ITypeHierarchy fHierarchy; 152 153 private Map fTypeToMemberArray; 155 public PullUpHierarchyContentProvider(final IType declaringType, final IMember[] members) { 156 fDeclaringType= declaringType; 157 fTypeToMemberArray= PullUpMethodPage.createTypeToMemberArrayMapping(members); 158 } 159 160 public void dispose() { 161 fHierarchy= null; 162 fTypeToMemberArray.clear(); 163 fTypeToMemberArray= null; 164 fDeclaringType= null; 165 } 166 167 public Object [] getChildren(final Object parentElement) { 168 if (parentElement instanceof IType) 169 return getSubclassesAndMembers((IType) parentElement); 170 else 171 return new Object [0]; 172 } 173 174 public Object [] getElements(final Object inputElement) { 175 Assert.isTrue(inputElement == null || inputElement instanceof ITypeHierarchy); 176 return new IType[] { fHierarchy.getType()}; 177 } 178 179 private IMember[] getMembers(final IType type) { 180 if (fTypeToMemberArray.containsKey(type)) 181 return (IMember[]) (fTypeToMemberArray.get(type)); 182 else 183 return new IMember[0]; 184 } 185 186 public Object getParent(final Object element) { 187 if (element instanceof IType) 188 return fHierarchy.getSuperclass((IType) element); 189 if (element instanceof IMember) 190 return ((IMember) element).getDeclaringType(); 191 Assert.isTrue(false, "Should not get here"); return null; 193 } 194 195 private IType[] getSubclasses(final IType type) { 196 if (type.equals(fDeclaringType)) 197 return new IType[0]; 198 return fHierarchy.getSubclasses(type); 199 } 200 201 private Object [] getSubclassesAndMembers(final IType type) { 202 final Set set= new HashSet (); 203 set.addAll(Arrays.asList(getSubclasses(type))); 204 set.addAll(Arrays.asList(getMembers(type))); 205 return set.toArray(); 206 } 207 208 public boolean hasChildren(final Object element) { 209 if (!(element instanceof IType)) 210 return false; 211 final IType type= (IType) element; 212 return (fHierarchy.getAllSubtypes(type).length > 0) || fTypeToMemberArray.containsKey(type); 213 } 214 215 public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { 216 Assert.isTrue(newInput == null || newInput instanceof ITypeHierarchy); 217 fHierarchy= (ITypeHierarchy) newInput; 218 } 219 } 220 221 private static final String PAGE_NAME= "PullUpMethodPage"; 223 private static Map createTypeToMemberArrayMapping(final IMember[] members) { 225 final Map typeToMemberSet= createTypeToMemberSetMapping(members); 226 227 final Map typeToMemberArray= new HashMap (); 228 for (final Iterator iter= typeToMemberSet.keySet().iterator(); iter.hasNext();) { 229 final IType type= (IType) iter.next(); 230 final Set memberSet= (Set ) typeToMemberSet.get(type); 231 final IMember[] memberArray= (IMember[]) memberSet.toArray(new IMember[memberSet.size()]); 232 typeToMemberArray.put(type, memberArray); 233 } 234 return typeToMemberArray; 235 } 236 237 private static Map createTypeToMemberSetMapping(final IMember[] members) { 239 final Map typeToMemberSet= new HashMap (); 240 for (int i= 0; i < members.length; i++) { 241 final IMember member= members[i]; 242 final IType type= member.getDeclaringType(); 243 if (!typeToMemberSet.containsKey(type)) 244 typeToMemberSet.put(type, new HashSet ()); 245 ((Set ) typeToMemberSet.get(type)).add(member); 246 } 247 return typeToMemberSet; 248 } 249 250 private boolean fChangedSettings= true; 251 252 private Label fSelectionLabel; 253 254 private SourceViewer fSourceViewer; 255 256 private ContainerCheckedTreeViewer fTreeViewer; 257 258 private Label fTypeHierarchyLabel; 259 260 public PullUpMethodPage() { 261 super(PAGE_NAME); 262 setMessage(RefactoringMessages.PullUpInputPage_select_methods); 263 } 264 265 private void checkAllParents(final IType parent) { 266 final ITypeHierarchy th= getTreeInput(); 267 final IType root= getTreeInput().getType(); 268 IType type= parent; 269 while (!root.equals(type)) { 270 fTreeViewer.setChecked(type, true); 271 type= th.getSuperclass(type); 272 } 273 fTreeViewer.setChecked(root, true); 274 } 275 276 public void checkPulledUp() { 277 uncheckAll(); 278 final HierarchyProcessor processor= getPullUpRefactoring().getPullUpProcessor(); 279 fTreeViewer.setCheckedElements(processor.getMembersToMove()); 280 final IType parent= processor.getDeclaringType(); 281 fTreeViewer.setChecked(parent, true); 282 checkAllParents(parent); 283 } 284 285 private void createButtonComposite(final Composite superComposite) { 286 final Composite buttonComposite= new Composite(superComposite, SWT.NONE); 287 buttonComposite.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); 288 final GridLayout layout= new GridLayout(2, false); 289 layout.marginWidth= 0; 290 buttonComposite.setLayout(layout); 291 292 fSelectionLabel= new Label(buttonComposite, SWT.LEFT | SWT.WRAP | SWT.HORIZONTAL); 293 GridData data= new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false); 294 data.widthHint= convertWidthInCharsToPixels(32); 295 fSelectionLabel.setLayoutData(data); 296 297 final Button button= new Button(buttonComposite, SWT.PUSH); 298 button.setText(RefactoringMessages.PullUpInputPage2_Select); 299 button.setLayoutData(new GridData()); 300 SWTUtil.setButtonDimensionHint(button); 301 button.addSelectionListener(new SelectionAdapter() { 302 303 public void widgetSelected(final SelectionEvent e) { 304 checkPulledUp(); 305 updateSelectionLabel(); 306 } 307 }); 308 } 309 310 public void createControl(final Composite parent) { 311 final Composite composite= new Composite(parent, SWT.NONE); 312 composite.setLayout(new GridLayout()); 313 314 createTreeAndSourceViewer(composite); 315 createButtonComposite(composite); 316 setControl(composite); 317 318 Dialog.applyDialogFont(composite); 319 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.PULL_UP_WIZARD_PAGE); 320 } 321 322 private void createHierarchyTreeComposite(final Composite parent) { 323 final Composite composite= new Composite(parent, SWT.NONE); 324 composite.setLayoutData(new GridData(GridData.FILL_BOTH)); 325 final GridLayout layout= new GridLayout(); 326 layout.marginWidth= 0; 327 layout.marginHeight= 0; 328 layout.horizontalSpacing= 1; 329 layout.verticalSpacing= 1; 330 composite.setLayout(layout); 331 332 createTypeHierarchyLabel(composite); 333 createTreeViewer(composite); 334 } 335 336 private void createSourceViewer(final Composite c) { 337 final IPreferenceStore store= JavaPlugin.getDefault().getCombinedPreferenceStore(); 338 fSourceViewer= new JavaSourceViewer(c, null, null, false, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION, store); 339 fSourceViewer.configure(new JavaSourceViewerConfiguration(JavaPlugin.getDefault().getJavaTextTools().getColorManager(), store, null, null)); 340 fSourceViewer.setEditable(false); 341 fSourceViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); 342 fSourceViewer.getControl().setFont(JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT)); 343 } 344 345 private void createSourceViewerComposite(final Composite parent) { 346 final Composite c= new Composite(parent, SWT.NONE); 347 c.setLayoutData(new GridData(GridData.FILL_BOTH)); 348 final GridLayout layout= new GridLayout(); 349 layout.marginWidth= 0; 350 layout.marginHeight= 0; 351 layout.horizontalSpacing= 1; 352 layout.verticalSpacing= 1; 353 c.setLayout(layout); 354 355 createSourceViewerLabel(c); 356 createSourceViewer(c); 357 } 358 359 private void createSourceViewerLabel(final Composite c) { 360 final Label label= new Label(c, SWT.WRAP); 361 final GridData gd= new GridData(GridData.FILL_HORIZONTAL); 362 label.setText(RefactoringMessages.PullUpInputPage2_Source); 363 label.setLayoutData(gd); 364 } 365 366 private void createTreeAndSourceViewer(final Composite superComposite) { 367 final SashForm composite= new SashForm(superComposite, SWT.HORIZONTAL); 368 initializeDialogUnits(superComposite); 369 final GridData gd= new GridData(GridData.FILL_BOTH); 370 gd.heightHint= convertHeightInCharsToPixels(20); 371 gd.widthHint= convertWidthInCharsToPixels(10); 372 composite.setLayoutData(gd); 373 final GridLayout layout= new GridLayout(); 374 layout.numColumns= 2; 375 layout.marginWidth= 0; 376 layout.marginHeight= 0; 377 layout.horizontalSpacing= 1; 378 layout.verticalSpacing= 1; 379 composite.setLayout(layout); 380 381 createHierarchyTreeComposite(composite); 382 createSourceViewerComposite(composite); 383 composite.setWeights(new int[] { 50, 50}); 384 } 385 386 private void createTreeViewer(final Composite composite) { 387 final Tree tree= new Tree(composite, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL); 388 tree.setLayoutData(new GridData(GridData.FILL_BOTH)); 389 fTreeViewer= new ContainerCheckedTreeViewer(tree); 390 fTreeViewer.setLabelProvider(new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT | JavaElementLabelProvider.SHOW_SMALL_ICONS)); 391 fTreeViewer.setUseHashlookup(true); 392 fTreeViewer.setComparator(new JavaElementComparator()); 393 fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { 394 395 public void selectionChanged(final SelectionChangedEvent event) { 396 treeViewerSelectionChanged(event); 397 } 398 }); 399 fTreeViewer.addCheckStateListener(new ICheckStateListener() { 400 401 public void checkStateChanged(final CheckStateChangedEvent event) { 402 updateSelectionLabel(); 403 } 404 }); 405 } 406 407 private void createTypeHierarchyLabel(final Composite composite) { 408 fTypeHierarchyLabel= new Label(composite, SWT.WRAP); 409 final GridData gd= new GridData(GridData.FILL_HORIZONTAL); 410 fTypeHierarchyLabel.setLayoutData(gd); 411 } 412 413 public void fireSettingsChanged() { 414 fChangedSettings= true; 415 } 416 417 private IMethod[] getCheckedMethods() { 418 final Object [] checked= fTreeViewer.getCheckedElements(); 419 final List members= new ArrayList (checked.length); 420 for (int i= 0; i < checked.length; i++) { 421 if (checked[i] instanceof IMethod) 422 members.add(checked[i]); 423 } 424 return (IMethod[]) members.toArray(new IMethod[members.size()]); 425 } 426 427 private ISourceReference getFirstSelectedSourceReference(final SelectionChangedEvent event) { 428 final ISelection s= event.getSelection(); 429 if (!(s instanceof IStructuredSelection)) 430 return null; 431 final IStructuredSelection ss= (IStructuredSelection) s; 432 if (ss.size() != 1) 433 return null; 434 final Object first= ss.getFirstElement(); 435 if (!(first instanceof ISourceReference)) 436 return null; 437 return (ISourceReference) first; 438 } 439 440 public IWizardPage getNextPage() { 441 initializeRefactoring(); 442 return super.getNextPage(); 443 } 444 445 private PullUpRefactoring getPullUpRefactoring() { 446 return (PullUpRefactoring) getRefactoring(); 447 } 448 449 private String getSupertypeSignature() { 450 return JavaElementUtil.createSignature(getPullUpRefactoring().getPullUpProcessor().getDestinationType()); 451 } 452 453 private ITypeHierarchy getTreeInput() { 454 return (ITypeHierarchy) fTreeViewer.getInput(); 455 } 456 457 private void initializeRefactoring() { 458 getPullUpRefactoring().getPullUpProcessor().setDeletedMethods(getCheckedMethods()); 459 } 460 461 private void initializeTreeViewer() { 462 try { 463 getContainer().run(false, false, new IRunnableWithProgress() { 464 465 public void run(final IProgressMonitor pm) { 466 try { 467 initializeTreeViewer(pm); 468 } finally { 469 pm.done(); 470 } 471 } 472 }); 473 } catch (InvocationTargetException e) { 474 ExceptionHandler.handle(e, getShell(), RefactoringMessages.PullUpInputPage_pull_Up, RefactoringMessages.PullUpInputPage_exception); 475 } catch (InterruptedException e) { 476 Assert.isTrue(false); 477 } 478 } 479 480 private void initializeTreeViewer(final IProgressMonitor pm) { 481 try { 482 pm.beginTask(RefactoringCoreMessages.PullUpRefactoring_checking, 2); 483 final PullUpRefactoringProcessor processor= getPullUpRefactoring().getPullUpProcessor(); 484 final IMember[] matchingMethods= processor.getMatchingElements(new SubProgressMonitor(pm, 1), false); 485 final ITypeHierarchy hierarchy= processor.getDestinationTypeHierarchy(new SubProgressMonitor(pm, 1)); 486 removeAllTreeViewFilters(); 487 fTreeViewer.addFilter(new PullUpFilter(hierarchy, matchingMethods)); 488 fTreeViewer.setContentProvider(new PullUpHierarchyContentProvider(processor.getDeclaringType(), matchingMethods)); 489 fTreeViewer.setInput(hierarchy); 490 precheckElements(fTreeViewer); 491 fTreeViewer.expandAll(); 492 updateSelectionLabel(); 493 } catch (JavaModelException e) { 494 ExceptionHandler.handle(e, RefactoringMessages.PullUpInputPage_pull_up1, RefactoringMessages.PullUpInputPage_exception); 495 fTreeViewer.setInput(null); 496 } finally { 497 pm.done(); 498 } 499 } 500 501 protected boolean performFinish() { 502 initializeRefactoring(); 503 return super.performFinish(); 504 } 505 506 private void precheckElements(final ContainerCheckedTreeViewer treeViewer) { 507 final IMember[] members= getPullUpRefactoring().getPullUpProcessor().getMembersToMove(); 508 for (int i= 0; i < members.length; i++) { 509 treeViewer.setChecked(members[i], true); 510 } 511 } 512 513 private void removeAllTreeViewFilters() { 514 final ViewerFilter[] filters= fTreeViewer.getFilters(); 515 for (int i= 0; i < filters.length; i++) { 516 fTreeViewer.removeFilter(filters[i]); 517 } 518 } 519 520 private void setHierarchyLabelText() { 521 final String message= Messages.format(RefactoringMessages.PullUpInputPage_subtypes, getSupertypeSignature()); 522 fTypeHierarchyLabel.setText(message); 523 } 524 525 private void setSourceViewerContents(String contents) { 526 if (contents != null) { 527 final IJavaProject project= getPullUpRefactoring().getPullUpProcessor().getDestinationType().getJavaProject(); 528 final String [] lines= Strings.convertIntoLines(contents); 529 if (lines.length > 0) { 530 final int indent= Strings.computeIndentUnits(lines[lines.length - 1], project); 531 contents= Strings.changeIndent(contents, indent, project, "", "\n"); } 533 } 534 final IDocument document= (contents == null) ? new Document() : new Document(contents); 535 JavaPlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(document); 536 fSourceViewer.setDocument(document); 537 } 538 539 public void setVisible(final boolean visible) { 540 if (visible && fChangedSettings) { 541 fChangedSettings= false; 542 initializeTreeViewer(); 543 setHierarchyLabelText(); 544 } 545 super.setVisible(visible); 546 } 547 548 private void showInSourceViewer(final ISourceReference selected) throws JavaModelException { 549 if (selected == null) 550 setSourceViewerContents(null); 551 else 552 setSourceViewerContents(selected.getSource()); 553 } 554 555 private void treeViewerSelectionChanged(final SelectionChangedEvent event) { 556 try { 557 showInSourceViewer(getFirstSelectedSourceReference(event)); 558 } catch (JavaModelException e) { 559 ExceptionHandler.handle(e, RefactoringMessages.PullUpInputPage_pull_up1, RefactoringMessages.PullUpInputPage_see_log); 560 } 561 } 562 563 private void uncheckAll() { 564 final IType root= getTreeInput().getType(); 565 fTreeViewer.setChecked(root, false); 566 } 567 568 private void updateSelectionLabel() { 569 fSelectionLabel.setText(Messages.format(RefactoringMessages.PullUpInputPage_hierarchyLabal, String.valueOf(getCheckedMethods().length))); 570 } 571 } | Popular Tags |