| /******************************************************************************* |
| * Copyright (c) 2000, 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.jdt.internal.ui.refactoring; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.TreeItem; |
| |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.viewers.IColorProvider; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.LabelProviderChangedEvent; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.wizard.IWizardPage; |
| |
| import org.eclipse.ui.PlatformUI; |
| |
| import org.eclipse.ltk.ui.refactoring.RefactoringWizard; |
| import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; |
| |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| |
| import org.eclipse.jdt.internal.corext.refactoring.structure.ChangeTypeRefactoring; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; |
| |
| |
| /** |
| * @author tip |
| */ |
| public class ChangeTypeWizard extends RefactoringWizard { |
| |
| private ChangeTypeRefactoring fCT; |
| |
| public ChangeTypeWizard(ChangeTypeRefactoring ref) { |
| super(ref, DIALOG_BASED_USER_INTERFACE); |
| setDefaultPageTitle(RefactoringMessages.ChangeTypeWizard_title); |
| fCT= ref; |
| } |
| |
| /* non java-doc |
| * @see RefactoringWizard#addUserInputPages |
| */ |
| protected void addUserInputPages(){ |
| addPage(new ChangeTypeInputPage()); |
| } |
| |
| // For debugging |
| static String print(Collection/*<ITypeBinding>*/ types){ |
| if (types.isEmpty()) |
| return "{ }"; //$NON-NLS-1$ |
| String result = "{ "; //$NON-NLS-1$ |
| for (Iterator it=types.iterator(); it.hasNext(); ){ |
| ITypeBinding type= (ITypeBinding)it.next(); |
| result += type.getQualifiedName(); |
| if (it.hasNext()){ |
| result += ", "; //$NON-NLS-1$ |
| } else { |
| result += " }"; //$NON-NLS-1$ |
| } |
| } |
| return result; |
| } |
| |
| |
| /** |
| * A JavaElementLabelProvider that supports graying out of invalid types. |
| */ |
| private class ChangeTypeLabelProvider extends BindingLabelProvider |
| implements IColorProvider { |
| |
| private Color fGrayColor; |
| private HashMap/*<Image color, Image gray>*/ fGrayImages; |
| |
| public ChangeTypeLabelProvider(){ |
| fGrayColor= Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); |
| fGrayImages= new HashMap(); |
| } |
| |
| private Collection/*<ITypeBinding>*/ fInvalidTypes; |
| |
| public void grayOut(Collection/*<ITypeBinding>*/ invalidTypes){ |
| fInvalidTypes= invalidTypes; |
| /* |
| * Invalidate all labels. Invalidating only invalid types doesn't |
| * work since there can be multiple nodes in the tree that |
| * correspond to the same invalid IType. The TreeViewer only updates |
| * the label of one of these ITypes and leaves the others in their |
| * old state. |
| */ |
| fireLabelProviderChanged(new LabelProviderChangedEvent(this)); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) |
| */ |
| public Color getForeground(Object element) { |
| if (isInvalid(element)) |
| return fGrayColor; |
| else |
| return null; |
| } |
| |
| private boolean isInvalid(Object element) { |
| if (fInvalidTypes == null) |
| return false; // initially, everything is enabled |
| else |
| return fInvalidTypes.contains(element); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object) |
| */ |
| public Color getBackground(Object element) { |
| return null; |
| } |
| |
| /* |
| * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) |
| */ |
| public Image getImage(Object element) { |
| Image image= super.getImage(element); |
| if (isInvalid(element) && image != null) { |
| Image grayImage= (Image) fGrayImages.get(image); |
| if (grayImage == null) { |
| grayImage= new Image(Display.getCurrent(), image, SWT.IMAGE_GRAY); |
| fGrayImages.put(image, grayImage); |
| } |
| return grayImage; |
| } else { |
| return image; |
| } |
| } |
| |
| public void dispose() { |
| for (Iterator iter= fGrayImages.values().iterator(); iter.hasNext();) { |
| Image image= (Image) iter.next(); |
| image.dispose(); |
| } |
| fGrayImages.clear(); |
| super.dispose(); |
| } |
| } |
| |
| private class ChangeTypeInputPage extends UserInputWizardPage{ |
| |
| public static final String PAGE_NAME= "ChangeTypeInputPage";//$NON-NLS-1$ |
| private final String MESSAGE= RefactoringMessages.ChangeTypeInputPage_Select_Type; |
| private ChangeTypeLabelProvider fLabelProvider; |
| private TreeViewer fTreeViewer; |
| private boolean fTreeUpdated= false; |
| |
| public ChangeTypeInputPage() { |
| super(PAGE_NAME); |
| setMessage(MESSAGE); |
| } |
| |
| private class ValidTypesTask implements Runnable { |
| private Collection/*<ITypeBinding>*/ fInvalidTypes; |
| private Collection/*<ITypeBinding>*/ fValidTypes; |
| public void run() { |
| IRunnableWithProgress runnable= new IRunnableWithProgress() { |
| public void run(IProgressMonitor pm) { |
| pm.beginTask(RefactoringMessages.ChangeTypeWizard_analyzing, 1000); |
| ChangeTypeRefactoring ct= (ChangeTypeRefactoring)ChangeTypeWizard.this.getRefactoring(); |
| fInvalidTypes = new HashSet(); |
| fInvalidTypes.addAll(fCT.getAllSuperTypes(ct.getOriginalType())); |
| fValidTypes= ct.computeValidTypes(new SubProgressMonitor(pm, 950)); |
| fInvalidTypes.add(ct.getOriginalType()); |
| fInvalidTypes.removeAll(fValidTypes); |
| pm.worked(50); |
| pm.done(); |
| } |
| }; |
| boolean internalError= false; |
| try { |
| getWizard().getContainer().run(true, true, runnable); |
| } catch (InvocationTargetException e) { |
| internalError= true; |
| JavaPlugin.log(e); |
| ChangeTypeInputPage.this.setErrorMessage(RefactoringMessages.ChangeTypeWizard_internalError); |
| } catch (InterruptedException e) { |
| ChangeTypeInputPage.this.setMessage(RefactoringMessages.ChangeTypeWizard_computationInterrupted); |
| } |
| |
| fLabelProvider.grayOut(fInvalidTypes); |
| |
| if (internalError) { |
| setPageComplete(false); |
| } else if (fValidTypes == null || fValidTypes.size() == 0){ |
| ChangeTypeInputPage.this.setErrorMessage(RefactoringMessages.ChangeTypeWizard_declCannotBeChanged); |
| setPageComplete(false); |
| } else { |
| TreeItem selection= getInitialSelection(fValidTypes); |
| fTreeViewer.getTree().setSelection(new TreeItem[]{ selection }); |
| setPageComplete(true); |
| ChangeTypeInputPage.this.setMessage(""); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| private TreeItem getInitialSelection(Collection/*<ITypeBinding>*/ types) { |
| |
| // first, find a most general valid type (there may be more than one) |
| ITypeBinding type= (ITypeBinding)types.iterator().next(); |
| for (Iterator it= types.iterator(); it.hasNext(); ){ |
| ITypeBinding other= (ITypeBinding)it.next(); |
| if (getGeneralizeTypeRefactoring().isSubTypeOf(type, other)){ |
| type= other; |
| } |
| } |
| |
| // now find a corresponding TreeItem (there may be more than one) |
| return findItem(fTreeViewer.getTree().getItems(), type); |
| } |
| |
| private TreeItem findItem(TreeItem[] items, ITypeBinding type){ |
| for (int i=0; i < items.length; i++){ |
| if (items[i].getData().equals(type)) return items[i]; |
| } |
| for (int i=0; i < items.length; i++){ |
| TreeItem item= findItem(items[i].getItems(), type); |
| if (item != null) return item; |
| } |
| return null; |
| } |
| |
| |
| public void createControl(Composite parent) { |
| Composite composite= new Composite(parent, SWT.NONE); |
| setControl(composite); |
| composite.setLayout(new GridLayout()); |
| composite.setLayoutData(new GridData()); |
| |
| Label label= new Label(composite, SWT.NONE); |
| label.setText(Messages.format( |
| RefactoringMessages.ChangeTypeWizard_pleaseChooseType, |
| ((ChangeTypeRefactoring) getRefactoring()).getTarget())); |
| label.setLayoutData(new GridData()); |
| |
| addTreeComponent(composite); |
| Dialog.applyDialogFont(composite); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.CHANGE_TYPE_WIZARD_PAGE); |
| } |
| |
| /** |
| * Tree-viewer that shows the allowable types in a tree view. |
| */ |
| private void addTreeComponent(Composite parent) { |
| fTreeViewer= new TreeViewer(parent, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); |
| GridData gd= new GridData(GridData.FILL_BOTH); |
| gd.grabExcessHorizontalSpace= true; |
| gd.grabExcessVerticalSpace= true; |
| GC gc= null; |
| try { |
| gc= new GC(parent); |
| gc.setFont(gc.getFont()); |
| gd.heightHint= Dialog.convertHeightInCharsToPixels(gc.getFontMetrics(), 6); // 6 characters tall |
| } finally { |
| if (gc != null) { |
| gc.dispose(); |
| gc= null; |
| } |
| } |
| fTreeViewer.getTree().setLayoutData(gd); |
| |
| fTreeViewer.setContentProvider(new ChangeTypeContentProvider(((ChangeTypeRefactoring)getRefactoring()))); |
| fLabelProvider= new ChangeTypeLabelProvider(); |
| fTreeViewer.setLabelProvider(fLabelProvider); |
| ISelectionChangedListener listener= new ISelectionChangedListener(){ |
| public void selectionChanged(SelectionChangedEvent event) { |
| IStructuredSelection selection= (IStructuredSelection)event.getSelection(); |
| typeSelected((ITypeBinding)selection.getFirstElement()); |
| } |
| }; |
| fTreeViewer.addSelectionChangedListener(listener); |
| fTreeViewer.setInput(new ChangeTypeContentProvider.RootType(getGeneralizeTypeRefactoring().getOriginalType())); |
| fTreeViewer.expandToLevel(10); |
| } |
| |
| private void typeSelected(ITypeBinding type) { |
| boolean isValid= getGeneralizeTypeRefactoring().getValidTypes().contains(type); |
| ChangeTypeInputPage.this.setPageComplete(isValid); |
| if (isValid) { |
| ChangeTypeInputPage.this.setMessage(""); //$NON-NLS-1$ |
| } else { |
| if (getGeneralizeTypeRefactoring().getOriginalType().equals(type)) { |
| ChangeTypeInputPage.this.setMessage(Messages.format( |
| RefactoringMessages.ChangeTypeWizard_with_itself, type.getName())); |
| |
| } else { |
| ChangeTypeInputPage.this.setMessage(Messages.format( |
| RefactoringMessages.ChangeTypeWizard_grayed_types, |
| new Object[] {type.getName(), getGeneralizeTypeRefactoring().getOriginalType().getName()})); |
| } |
| } |
| } |
| |
| private ChangeTypeRefactoring getGeneralizeTypeRefactoring(){ |
| return (ChangeTypeRefactoring)getRefactoring(); |
| } |
| /* |
| * @see org.eclipse.jface.wizard.IWizardPage#getNextPage() |
| */ |
| public IWizardPage getNextPage() { |
| initializeRefactoring(); |
| return super.getNextPage(); |
| } |
| |
| private ITypeBinding getSelectedType() { |
| IStructuredSelection ss= (IStructuredSelection)fTreeViewer.getSelection(); |
| return (ITypeBinding)ss.getFirstElement(); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.ui.refactoring.RefactoringWizardPage#performFinish() |
| */ |
| public boolean performFinish(){ |
| initializeRefactoring(); |
| return super.performFinish(); |
| } |
| |
| private void initializeRefactoring() { |
| getGeneralizeTypeRefactoring().setSelectedType(getSelectedType()); |
| } |
| |
| /* |
| * @see org.eclipse.jface.dialogs.IDialogPage#dispose() |
| */ |
| public void dispose() { |
| fTreeViewer= null; |
| super.dispose(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean) |
| */ |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| if (visible && fTreeViewer != null) |
| fTreeViewer.getTree().setFocus(); |
| if (!fTreeUpdated){ |
| fTreeViewer.getTree().getDisplay().asyncExec(new ValidTypesTask()); |
| fTreeUpdated= true; |
| } |
| } |
| } |
| } |