blob: 21d4abd0d44303663b25e69a871455136b15055d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 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
* Philippe Ombredanne - bug 149382
*******************************************************************************/
package org.eclipse.jdt.ui.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.text.IRewriteTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.corext.codemanipulation.AddGetterSetterOperation;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil;
import org.eclipse.jdt.internal.corext.codemanipulation.IRequestQuery;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.template.java.CodeTemplateContextType;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementComparator;
import org.eclipse.jdt.ui.JavaElementImageDescriptor;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.ActionMessages;
import org.eclipse.jdt.internal.ui.actions.ActionUtil;
import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
import org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog;
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
import org.eclipse.jdt.internal.ui.util.ElementValidator;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
/**
* Creates getter and setter methods for a type's fields. Opens a dialog with a list of
* fields for which a setter or getter can be generated. User is able to check or uncheck
* items before setters or getters are generated.
* <p>
* Will open the parent compilation unit in a Java editor. The result is unsaved, so the
* user can decide if the changes are acceptable.
* <p>
* The action is applicable to structured selections containing elements of type
* <code>IField</code> or <code>IType</code>.
*
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*
* @since 2.0
*
* @noextend This class is not intended to be subclassed by clients.
*/
public class AddGetterSetterAction extends SelectionDispatchAction {
private boolean fSort;
private boolean fSynchronized;
private boolean fFinal;
private int fVisibility;
private boolean fGenerateComment;
private int fNumEntries;
private CompilationUnitEditor fEditor;
private static final String DIALOG_TITLE= ActionMessages.AddGetterSetterAction_error_title;
/**
* Creates a new <code>AddGetterSetterAction</code>. The action requires that the
* selection provided by the site's selection provider is of type <code>
* org.eclipse.jface.viewers.IStructuredSelection</code>.
*
* @param site the site providing context information for this action
*/
public AddGetterSetterAction(IWorkbenchSite site) {
super(site);
setText(ActionMessages.AddGetterSetterAction_label);
setDescription(ActionMessages.AddGetterSetterAction_description);
setToolTipText(ActionMessages.AddGetterSetterAction_tooltip);
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.GETTERSETTER_ACTION);
}
/**
* Note: This constructor is for internal use only. Clients should not call this
* constructor.
*
* @param editor the compilation unit editor
*
* @noreference This constructor is not intended to be referenced by clients.
*/
public AddGetterSetterAction(CompilationUnitEditor editor) {
this(editor.getEditorSite());
fEditor= editor;
setEnabled(SelectionConverter.getInputAsCompilationUnit(editor) != null);
fEditor.getEditorSite();
}
// ---- Structured Viewer -----------------------------------------------------------
/*
* (non-Javadoc) Method declared on SelectionDispatchAction
*/
@Override
public void selectionChanged(IStructuredSelection selection) {
try {
setEnabled(canEnable(selection));
} catch (JavaModelException e) {
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
if (JavaModelUtil.isExceptionToBeLogged(e))
JavaPlugin.log(e);
setEnabled(false);
}
}
/*
* (non-Javadoc) Method declared on SelectionDispatchAction
*/
@Override
public void run(IStructuredSelection selection) {
try {
IField[] selectedFields= getSelectedFields(selection);
if (canRunOn(selectedFields)) {
run(selectedFields[0].getDeclaringType(), selectedFields, false);
return;
}
Object firstElement= selection.getFirstElement();
if (firstElement instanceof IType)
run((IType) firstElement, new IField[0], false);
else if (firstElement instanceof ICompilationUnit) {
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=38500
IType type= ((ICompilationUnit) firstElement).findPrimaryType();
// type can be null if file has a bad encoding
if (type == null) {
MessageDialog.openError(getShell(),
ActionMessages.AddGetterSetterAction_no_primary_type_title,
ActionMessages.AddGetterSetterAction_no_primary_type_message);
notifyResult(false);
return;
}
if (type.isAnnotation()) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_annotation_not_applicable);
notifyResult(false);
return;
} else if (type.isInterface()) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_interface_not_applicable);
notifyResult(false);
return;
} else
run(((ICompilationUnit) firstElement).findPrimaryType(), new IField[0], false);
}
} catch (CoreException e) {
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_error_actionfailed);
}
}
private boolean canEnable(IStructuredSelection selection) throws JavaModelException {
if (getSelectedFields(selection) != null)
return true;
if ((selection.size() == 1) && (selection.getFirstElement() instanceof IType)) {
IType type= (IType) selection.getFirstElement();
return type.getCompilationUnit() != null && !type.isInterface() && !type.isAnonymous();
}
if ((selection.size() == 1) && (selection.getFirstElement() instanceof ICompilationUnit))
return true;
return false;
}
private boolean canRunOn(IField[] fields) throws JavaModelException {
if (fields == null || fields.length == 0)
return false;
int count= 0;
for (int index= 0; index < fields.length; index++) {
if (!JdtFlags.isEnum(fields[index]))
count++;
}
if (count == 0)
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_not_applicable);
return (count > 0);
}
private void resetNumEntries() {
fNumEntries= 0;
}
private void incNumEntries() {
fNumEntries++;
}
private void run(IType type, IField[] preselected, boolean editor) throws CoreException {
if (type.isAnnotation()) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_annotation_not_applicable);
notifyResult(false);
return;
} else if (type.isInterface()) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_interface_not_applicable);
notifyResult(false);
return;
} else if (type.getCompilationUnit() == null) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_error_not_in_source_file);
notifyResult(false);
return;
}
if (!ElementValidator.check(type, getShell(), DIALOG_TITLE, editor)) {
notifyResult(false);
return;
}
if (!ActionUtil.isEditable(getShell(), type)) {
notifyResult(false);
return;
}
ILabelProvider lp= new AddGetterSetterLabelProvider();
resetNumEntries();
Map<IField, GetterSetterEntry[]> entries= createGetterSetterMapping(type);
if (entries.isEmpty()) {
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGettSetterAction_typeContainsNoFields_message);
notifyResult(false);
return;
}
AddGetterSetterContentProvider cp= new AddGetterSetterContentProvider(entries);
GetterSetterTreeSelectionDialog dialog= new GetterSetterTreeSelectionDialog(getShell(), lp, cp, fEditor, type);
dialog.setComparator(new JavaElementComparator());
dialog.setTitle(DIALOG_TITLE);
String message= ActionMessages.AddGetterSetterAction_dialog_label;
dialog.setMessage(message);
dialog.setValidator(createValidator(fNumEntries));
dialog.setContainerMode(true);
dialog.setSize(60, 18);
dialog.setInput(type);
if (preselected.length > 0) {
dialog.setInitialSelections(preselected);
dialog.setExpandedElements(preselected);
}
final Set<IField> keySet= new LinkedHashSet<IField>(entries.keySet());
int dialogResult= dialog.open();
if (dialogResult == Window.OK) {
Object[] result= dialog.getResult();
if (result == null) {
notifyResult(false);
return;
}
fSort= dialog.getSortOrder();
fSynchronized= dialog.getSynchronized();
fFinal= dialog.getFinal();
fVisibility= dialog.getVisibilityModifier();
fGenerateComment= dialog.getGenerateComment();
IField[] getterFields, setterFields, getterSetterFields;
if (fSort) {
getterFields= getGetterFields(result, keySet);
setterFields= getSetterFields(result, keySet);
getterSetterFields= new IField[0];
} else {
getterFields= getGetterOnlyFields(result, keySet);
setterFields= getSetterOnlyFields(result, keySet);
getterSetterFields= getGetterSetterFields(result, keySet);
}
generate(type, getterFields, setterFields, getterSetterFields, new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(type.getCompilationUnit(), true), dialog.getElementPosition());
}
notifyResult(dialogResult == Window.OK);
}
private static class AddGetterSetterSelectionStatusValidator implements ISelectionStatusValidator {
private static int fEntries;
AddGetterSetterSelectionStatusValidator(int entries) {
fEntries= entries;
}
public IStatus validate(Object[] selection) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=38478
HashSet<Object> map= null;
if ((selection != null) && (selection.length > 1)) {
map= new HashSet<Object>(selection.length);
}
int selectedCount= 0;
int possibleDuplicateCount= 0;
for (int i= 0; i < selection.length; i++) {
try {
if (selection[i] instanceof GetterSetterEntry) {
Object key= selection[i];
IField getsetField= ((GetterSetterEntry) selection[i]).field;
if (((GetterSetterEntry) selection[i]).isGetter) {
if (!map.add(GetterSetterUtil.getGetterName(getsetField, null)))
possibleDuplicateCount++;
} else {
key= createSignatureKey(GetterSetterUtil.getSetterName(getsetField, null), getsetField);
if (!map.add(key))
possibleDuplicateCount++;
}
selectedCount++;
}
} catch (JavaModelException e) {
}
}
if (possibleDuplicateCount > 0) {
return new StatusInfo(IStatus.WARNING, possibleDuplicateCount == 1
? ActionMessages.AddGetterSetterAction_error_duplicate_methods_singular
: Messages.format(ActionMessages.AddGetterSetterAction_error_duplicate_methods_plural, String.valueOf(possibleDuplicateCount)));
}
if (selectedCount == 0)
return new StatusInfo(IStatus.ERROR, ""); //$NON-NLS-1$
String message= Messages.format(ActionMessages.AddGetterSetterAction_methods_selected,
new Object[] { String.valueOf(selectedCount), String.valueOf(fEntries)});
return new StatusInfo(IStatus.INFO, message);
}
}
/**
* Creates a key used in hash maps for a method signature (gettersettername+arguments(fqn)).
*
* @param methodName the method name
* @param field the filed
* @return the signature
* @throws JavaModelException if getting the field's type signature fails
*/
private static String createSignatureKey(String methodName, IField field) throws JavaModelException {
StringBuffer buffer= new StringBuffer();
buffer.append(methodName);
String fieldType= field.getTypeSignature();
String signature= Signature.getSimpleName(Signature.toString(fieldType));
buffer.append("#"); //$NON-NLS-1$
buffer.append(signature);
return buffer.toString();
}
private static ISelectionStatusValidator createValidator(int entries) {
AddGetterSetterSelectionStatusValidator validator= new AddGetterSetterSelectionStatusValidator(entries);
return validator;
}
// returns a list of fields with setter entries checked
private static IField[] getSetterFields(Object[] result, Set<IField> set) {
List<IField> list= new ArrayList<IField>(0);
Object each= null;
GetterSetterEntry entry= null;
for (int i= 0; i < result.length; i++) {
each= result[i];
if ((each instanceof GetterSetterEntry)) {
entry= (GetterSetterEntry) each;
if (!entry.isGetter) {
list.add(entry.field);
}
}
}
list= reorderFields(list, set);
return list.toArray(new IField[list.size()]);
}
// returns a list of fields with getter entries checked
private static IField[] getGetterFields(Object[] result, Set<IField> set) {
List<IField> list= new ArrayList<IField>(0);
Object each= null;
GetterSetterEntry entry= null;
for (int i= 0; i < result.length; i++) {
each= result[i];
if ((each instanceof GetterSetterEntry)) {
entry= (GetterSetterEntry) each;
if (entry.isGetter) {
list.add(entry.field);
}
}
}
list= reorderFields(list, set);
return list.toArray(new IField[list.size()]);
}
// returns a list of fields with only getter entries checked
private static IField[] getGetterOnlyFields(Object[] result, Set<IField> set) {
List<IField> list= new ArrayList<IField>(0);
Object each= null;
GetterSetterEntry entry= null;
boolean getterSet= false;
for (int i= 0; i < result.length; i++) {
each= result[i];
if ((each instanceof GetterSetterEntry)) {
entry= (GetterSetterEntry) each;
if (entry.isGetter) {
list.add(entry.field);
getterSet= true;
}
if ((!entry.isGetter) && (getterSet == true)) {
list.remove(entry.field);
getterSet= false;
}
} else
getterSet= false;
}
list= reorderFields(list, set);
return list.toArray(new IField[list.size()]);
}
// returns a list of fields with only setter entries checked
private static IField[] getSetterOnlyFields(Object[] result, Set<IField> set) {
List<IField> list= new ArrayList<IField>(0);
Object each= null;
GetterSetterEntry entry= null;
boolean getterSet= false;
for (int i= 0; i < result.length; i++) {
each= result[i];
if ((each instanceof GetterSetterEntry)) {
entry= (GetterSetterEntry) each;
if (entry.isGetter) {
getterSet= true;
}
if ((!entry.isGetter) && (getterSet != true)) {
list.add(entry.field);
getterSet= false;
}
} else
getterSet= false;
}
list= reorderFields(list, set);
return list.toArray(new IField[list.size()]);
}
// returns a list of fields with both entries checked
private static IField[] getGetterSetterFields(Object[] result, Set<IField> set) {
List<IField> list= new ArrayList<IField>(0);
Object each= null;
GetterSetterEntry entry= null;
boolean getterSet= false;
for (int i= 0; i < result.length; i++) {
each= result[i];
if ((each instanceof GetterSetterEntry)) {
entry= (GetterSetterEntry) each;
if (entry.isGetter) {
getterSet= true;
}
if ((!entry.isGetter) && (getterSet == true)) {
list.add(entry.field);
getterSet= false;
}
} else
getterSet= false;
}
list= reorderFields(list, set);
return list.toArray(new IField[list.size()]);
}
private static List<IField> reorderFields(List<IField> collection, Set<IField> set) {
final List<IField> list= new ArrayList<IField>(collection.size());
for (final Iterator<IField> iterator= set.iterator(); iterator.hasNext();) {
final IField field= iterator.next();
if (collection.contains(field))
list.add(field);
}
return list;
}
private void generate(IType type, IField[] getterFields, IField[] setterFields, IField[] getterSetterFields, CompilationUnit unit, IJavaElement elementPosition) throws CoreException {
if (getterFields.length == 0 && setterFields.length == 0 && getterSetterFields.length == 0)
return;
ICompilationUnit cu= null;
if (getterFields.length != 0)
cu= getterFields[0].getCompilationUnit();
else if (setterFields.length != 0)
cu= setterFields[0].getCompilationUnit();
else
cu= getterSetterFields[0].getCompilationUnit();
// open the editor, forces the creation of a working copy
run(cu, type, getterFields, setterFields, getterSetterFields, JavaUI.openInEditor(cu), unit, elementPosition);
}
// ---- Java Editor --------------------------------------------------------------
/*
* (non-Javadoc) Method declared on SelectionDispatchAction
*/
@Override
public void selectionChanged(ITextSelection selection) {
}
/*
* (non-Javadoc) Method declared on SelectionDispatchAction
*/
@Override
public void run(ITextSelection selection) {
try {
if (!ActionUtil.isProcessable(fEditor)) {
notifyResult(false);
return;
}
IJavaElement[] elements= SelectionConverter.codeResolveForked(fEditor, true);
if (elements.length == 1 && (elements[0] instanceof IField)) {
IField field= (IField) elements[0];
run(field.getDeclaringType(), new IField[] { field}, true);
return;
}
IJavaElement element= SelectionConverter.getElementAtOffset(fEditor);
if (element != null) {
IType type= (IType) element.getAncestor(IJavaElement.TYPE);
if (type != null) {
if (type.getFields().length > 0) {
run(type, new IField[0], true);
return;
}
}
}
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_not_applicable);
} catch (CoreException e) {
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_error_actionfailed);
} catch (InvocationTargetException e) {
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.AddGetterSetterAction_error_actionfailed);
} catch (InterruptedException e) {
// cancelled
}
}
// ---- Helpers -------------------------------------------------------------------
private void run(ICompilationUnit cu, IType type, IField[] getterFields, IField[] setterFields, IField[] getterSetterFields, IEditorPart editor, CompilationUnit unit, IJavaElement elementPosition) {
IRewriteTarget target= editor.getAdapter(IRewriteTarget.class);
if (target != null) {
target.beginCompoundChange();
}
try {
CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
settings.createComments= fGenerateComment;
AddGetterSetterOperation op= new AddGetterSetterOperation(type, getterFields, setterFields, getterSetterFields, unit, skipReplaceQuery(), elementPosition, settings, true, false);
setOperationStatusFields(op);
IRunnableContext context= JavaPlugin.getActiveWorkbenchWindow();
if (context == null) {
context= new BusyIndicatorRunnableContext();
}
PlatformUI.getWorkbench().getProgressService().runInUI(context, new WorkbenchRunnableAdapter(op, op.getSchedulingRule()), op.getSchedulingRule());
} catch (InvocationTargetException e) {
String message= ActionMessages.AddGetterSetterAction_error_actionfailed;
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, message);
} catch (InterruptedException e) {
// operation canceled
} finally {
if (target != null) {
target.endCompoundChange();
}
}
}
private void setOperationStatusFields(AddGetterSetterOperation op) {
// Set the status fields corresponding to the visibility and modifiers set
int flags= fVisibility;
if (fSynchronized) {
flags|= Flags.AccSynchronized;
}
if (fFinal) {
flags|= Flags.AccFinal;
}
op.setSort(fSort);
op.setVisibility(flags);
}
private IRequestQuery skipReplaceQuery() {
return new IRequestQuery() {
public int doQuery(IMember method) {
int[] returnCodes= { IRequestQuery.YES, IRequestQuery.NO, IRequestQuery.YES_ALL, IRequestQuery.CANCEL};
String skipLabel= ActionMessages.AddGetterSetterAction_SkipExistingDialog_skip_label;
String replaceLabel= ActionMessages.AddGetterSetterAction_SkipExistingDialog_replace_label;
String skipAllLabel= ActionMessages.AddGetterSetterAction_SkipExistingDialog_skipAll_label;
String[] options= { skipLabel, replaceLabel, skipAllLabel, IDialogConstants.CANCEL_LABEL};
String methodName= JavaElementLabels.getElementLabel(method, JavaElementLabels.M_PARAMETER_TYPES);
String formattedMessage= Messages.format(ActionMessages.AddGetterSetterAction_SkipExistingDialog_message, BasicElementLabels.getJavaElementName(methodName));
return showQueryDialog(formattedMessage, options, returnCodes);
}
};
}
private int showQueryDialog(final String message, final String[] buttonLabels, int[] returnCodes) {
final Shell shell= getShell();
if (shell == null) {
JavaPlugin.logErrorMessage("AddGetterSetterAction.showQueryDialog: No active shell found"); //$NON-NLS-1$
return IRequestQuery.CANCEL;
}
final int[] result= { Window.CANCEL};
shell.getDisplay().syncExec(new Runnable() {
public void run() {
String title= ActionMessages.AddGetterSetterAction_QueryDialog_title;
MessageDialog dialog= new MessageDialog(shell, title, null, message, MessageDialog.QUESTION, buttonLabels, 0);
result[0]= dialog.open();
}
});
int returnVal= result[0];
return returnVal < 0 ? IRequestQuery.CANCEL : returnCodes[returnVal];
}
/*
* Returns fields in the selection or <code>null</code> if the selection is empty or
* not valid.
*/
private IField[] getSelectedFields(IStructuredSelection selection) {
List<?> elements= selection.toList();
int nElements= elements.size();
if (nElements > 0) {
IField[] res= new IField[nElements];
ICompilationUnit cu= null;
for (int i= 0; i < nElements; i++) {
Object curr= elements.get(i);
if (curr instanceof IField) {
IField fld= (IField) curr;
if (i == 0) {
// remember the cu of the first element
cu= fld.getCompilationUnit();
if (cu == null) {
return null;
}
} else if (!cu.equals(fld.getCompilationUnit())) {
// all fields must be in the same CU
return null;
}
try {
final IType declaringType= fld.getDeclaringType();
if (declaringType.isInterface() || declaringType.isAnonymous())
return null;
} catch (JavaModelException e) {
JavaPlugin.log(e);
return null;
}
res[i]= fld;
} else {
return null;
}
}
return res;
}
return null;
}
private static class AddGetterSetterLabelProvider extends JavaElementLabelProvider {
AddGetterSetterLabelProvider() {
}
/*
* @see ILabelProvider#getText(Object)
*/
@Override
public String getText(Object element) {
if (element instanceof GetterSetterEntry) {
GetterSetterEntry entry= (GetterSetterEntry) element;
try {
if (entry.isGetter) {
return GetterSetterUtil.getGetterName(entry.field, null) + "()"; //$NON-NLS-1$
} else {
return GetterSetterUtil.getSetterName(entry.field, null) + '(' + Signature.getSimpleName(Signature.toString(entry.field.getTypeSignature())) + ')';
}
} catch (JavaModelException e) {
return ""; //$NON-NLS-1$
}
}
return super.getText(element);
}
/*
* @see ILabelProvider#getImage(Object)
*/
@Override
public Image getImage(Object element) {
if (element instanceof GetterSetterEntry) {
int flags= 0;
try {
flags= ((GetterSetterEntry) element).field.getFlags();
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
ImageDescriptor desc= JavaElementImageProvider.getFieldImageDescriptor(false, Flags.AccPublic);
int adornmentFlags= Flags.isStatic(flags) ? JavaElementImageDescriptor.STATIC : 0;
desc= new JavaElementImageDescriptor(desc, adornmentFlags, JavaElementImageProvider.BIG_SIZE);
return JavaPlugin.getImageDescriptorRegistry().get(desc);
}
return super.getImage(element);
}
}
/**
* @param type the type
* @return map IField -> GetterSetterEntry[]
* @throws JavaModelException if the type does not exist or if an exception occurs while
* accessing its corresponding resource
*/
private Map<IField, GetterSetterEntry[]> createGetterSetterMapping(IType type) throws JavaModelException {
IField[] fields= type.getFields();
Map<IField, GetterSetterEntry[]> result= new LinkedHashMap<IField, GetterSetterEntry[]>();
for (int i= 0; i < fields.length; i++) {
IField field= fields[i];
int flags= field.getFlags();
if (!Flags.isEnum(flags)) {
List<GetterSetterEntry> l= new ArrayList<GetterSetterEntry>(2);
if (GetterSetterUtil.getGetter(field) == null) {
l.add(new GetterSetterEntry(field, true, Flags.isFinal(flags)));
incNumEntries();
}
if (GetterSetterUtil.getSetter(field) == null) {
l.add(new GetterSetterEntry(field, false, Flags.isFinal(flags)));
incNumEntries();
}
if (!l.isEmpty())
result.put(field, l.toArray(new GetterSetterEntry[l.size()]));
}
}
return result;
}
private static class AddGetterSetterContentProvider implements ITreeContentProvider {
private static final Object[] EMPTY= new Object[0];
private Map<IField, GetterSetterEntry[]> fGetterSetterEntries;
public AddGetterSetterContentProvider(Map<IField, GetterSetterEntry[]> entries) {
fGetterSetterEntries= entries;
}
/*
* @see IContentProvider#inputChanged(Viewer, Object, Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
/*
* @see ITreeContentProvider#getChildren(Object)
*/
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof IField)
return fGetterSetterEntries.get(parentElement);
return EMPTY;
}
/*
* @see ITreeContentProvider#getParent(Object)
*/
public Object getParent(Object element) {
if (element instanceof IMember)
return ((IMember) element).getDeclaringType();
if (element instanceof GetterSetterEntry)
return ((GetterSetterEntry) element).field;
return null;
}
/*
* @see ITreeContentProvider#hasChildren(Object)
*/
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
/*
* @see IStructuredContentProvider#getElements(Object)
*/
public Object[] getElements(Object inputElement) {
return fGetterSetterEntries.keySet().toArray();
}
/*
* @see IContentProvider#dispose()
*/
public void dispose() {
fGetterSetterEntries.clear();
fGetterSetterEntries= null;
}
}
private static class SettersForFinalFieldsFilter extends ViewerFilter {
private final AddGetterSetterContentProvider fContentProvider;
public SettersForFinalFieldsFilter(AddGetterSetterContentProvider contentProvider) {
fContentProvider= contentProvider;
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof GetterSetterEntry) {
GetterSetterEntry getterSetterEntry= (GetterSetterEntry) element;
return getterSetterEntry.isGetter || !getterSetterEntry.isFinal;
} else if (element instanceof IField) {
Object[] children= fContentProvider.getChildren(element);
for (int i= 0; i < children.length; i++) {
GetterSetterEntry curr= (GetterSetterEntry) children[i];
if (curr.isGetter || !curr.isFinal) {
return true;
}
}
return false;
}
return true;
}
}
private static class GetterSetterTreeSelectionDialog extends SourceActionDialog {
private AddGetterSetterContentProvider fContentProvider;
private static final int SELECT_GETTERS_ID= IDialogConstants.CLIENT_ID + 1;
private static final int SELECT_SETTERS_ID= IDialogConstants.CLIENT_ID + 2;
private final String SETTINGS_SECTION= "AddGetterSetterDialog"; //$NON-NLS-1$
private final String SORT_ORDER= "SortOrdering"; //$NON-NLS-1$
private final String ALLOW_SETTERS_FOR_FINALS= "RemoveFinal"; //$NON-NLS-1$
private IDialogSettings fSettings;
private SettersForFinalFieldsFilter fSettersForFinalFieldsFilter;
private boolean fSortOrder;
private boolean fAllowSettersForFinals;
private ArrayList<GetterSetterEntry> fPreviousSelectedFinals;
public GetterSetterTreeSelectionDialog(Shell parent, ILabelProvider labelProvider, AddGetterSetterContentProvider contentProvider, CompilationUnitEditor editor, IType type) throws JavaModelException {
super(parent, labelProvider, contentProvider, editor, type, false);
fContentProvider= contentProvider;
fPreviousSelectedFinals= new ArrayList<GetterSetterEntry>();
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
IDialogSettings dialogSettings= JavaPlugin.getDefault().getDialogSettings();
fSettings= dialogSettings.getSection(SETTINGS_SECTION);
if (fSettings == null) {
fSettings= dialogSettings.addNewSection(SETTINGS_SECTION);
fSettings.put(SORT_ORDER, false);
fSettings.put(ALLOW_SETTERS_FOR_FINALS, false);
}
fSortOrder= fSettings.getBoolean(SORT_ORDER);
fAllowSettersForFinals= fSettings.getBoolean(ALLOW_SETTERS_FOR_FINALS);
fSettersForFinalFieldsFilter= new SettersForFinalFieldsFilter(contentProvider);
}
public boolean getSortOrder() {
return fSortOrder;
}
public void setSortOrder(boolean sort) {
if (fSortOrder != sort) {
fSortOrder= sort;
fSettings.put(SORT_ORDER, sort);
if (getTreeViewer() != null) {
getTreeViewer().refresh();
}
}
}
private boolean allowSettersForFinals() {
return fAllowSettersForFinals;
}
public void allowSettersForFinals(boolean allowSettersForFinals) {
if (fAllowSettersForFinals != allowSettersForFinals) {
fAllowSettersForFinals= allowSettersForFinals;
fSettings.put(ALLOW_SETTERS_FOR_FINALS, allowSettersForFinals);
CheckboxTreeViewer treeViewer= getTreeViewer();
if (treeViewer != null) {
ArrayList<GetterSetterEntry> newChecked= new ArrayList<GetterSetterEntry>();
if (allowSettersForFinals) {
newChecked.addAll(fPreviousSelectedFinals);
}
fPreviousSelectedFinals.clear();
Object[] checkedElements= treeViewer.getCheckedElements();
for (int i= 0; i < checkedElements.length; i++) {
if (checkedElements[i] instanceof GetterSetterEntry) {
GetterSetterEntry entry= (GetterSetterEntry) checkedElements[i];
if (allowSettersForFinals || entry.isGetter || !entry.isFinal) {
newChecked.add(entry);
} else {
fPreviousSelectedFinals.add(entry);
}
}
}
if (allowSettersForFinals) {
treeViewer.removeFilter(fSettersForFinalFieldsFilter);
} else {
treeViewer.addFilter(fSettersForFinalFieldsFilter);
}
treeViewer.setCheckedElements(newChecked.toArray());
}
updateOKStatus();
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.dialogs.CheckedTreeSelectionDialog#createTreeViewer(org.eclipse.swt.widgets.Composite)
*/
@Override
protected CheckboxTreeViewer createTreeViewer(Composite parent) {
CheckboxTreeViewer treeViewer= super.createTreeViewer(parent);
if (!fAllowSettersForFinals) {
treeViewer.addFilter(fSettersForFinalFieldsFilter);
}
return treeViewer;
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IJavaHelpContextIds.ADD_GETTER_SETTER_SELECTION_DIALOG);
}
private void createGetterSetterButtons(Composite buttonComposite) {
createButton(buttonComposite, SELECT_GETTERS_ID, ActionMessages.GetterSetterTreeSelectionDialog_select_getters, false);
createButton(buttonComposite, SELECT_SETTERS_ID, ActionMessages.GetterSetterTreeSelectionDialog_select_setters, false);
}
@Override
protected void buttonPressed(int buttonId) {
super.buttonPressed(buttonId);
switch (buttonId) {
case SELECT_GETTERS_ID: {
getTreeViewer().setCheckedElements(getGetterSetterElements(true));
updateOKStatus();
break;
}
case SELECT_SETTERS_ID: {
getTreeViewer().setCheckedElements(getGetterSetterElements(false));
updateOKStatus();
break;
}
}
}
@Override
protected Composite createInsertPositionCombo(Composite composite) {
Button addRemoveFinalCheckbox= addAllowSettersForFinalslCheckbox(composite);
addRemoveFinalCheckbox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Composite entryComposite= super.createInsertPositionCombo(composite);
addSortOrder(entryComposite);
addVisibilityAndModifiersChoices(entryComposite);
return entryComposite;
}
private Button addAllowSettersForFinalslCheckbox(Composite entryComposite) {
Button allowSettersForFinalsButton= new Button(entryComposite, SWT.CHECK);
allowSettersForFinalsButton.setText(ActionMessages.AddGetterSetterAction_allow_setters_for_finals_description);
allowSettersForFinalsButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
boolean isSelected= (((Button) e.widget).getSelection());
allowSettersForFinals(isSelected);
}
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
allowSettersForFinalsButton.setSelection(allowSettersForFinals());
return allowSettersForFinalsButton;
}
private Composite addSortOrder(Composite composite) {
Label label= new Label(composite, SWT.NONE);
label.setText(ActionMessages.GetterSetterTreeSelectionDialog_sort_label);
GridData gd= new GridData(GridData.FILL_BOTH);
label.setLayoutData(gd);
final Combo combo= new Combo(composite, SWT.READ_ONLY);
combo.setItems(new String[] { ActionMessages.GetterSetterTreeSelectionDialog_alpha_pair_sort,
ActionMessages.GetterSetterTreeSelectionDialog_alpha_method_sort});
final int methodIndex= 1; // Hard-coded. Change this if the
// list gets more complicated.
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=38400
int sort= getSortOrder() ? 1 : 0;
combo.setText(combo.getItem(sort));
gd= new GridData(GridData.FILL_BOTH);
combo.setLayoutData(gd);
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setSortOrder(combo.getSelectionIndex() == methodIndex);
}
});
return composite;
}
private Object[] getGetterSetterElements(boolean isGetter) {
Object[] allFields= fContentProvider.getElements(null);
Set<GetterSetterEntry> result= new HashSet<GetterSetterEntry>();
for (int i= 0; i < allFields.length; i++) {
IField field= (IField) allFields[i];
GetterSetterEntry[] entries= getEntries(field);
for (int j= 0; j < entries.length; j++) {
AddGetterSetterAction.GetterSetterEntry entry= entries[j];
if (entry.isGetter == isGetter)
result.add(entry);
}
}
return result.toArray();
}
private GetterSetterEntry[] getEntries(IField field) {
List<Object> result= Arrays.asList(fContentProvider.getChildren(field));
return result.toArray(new GetterSetterEntry[result.size()]);
}
@Override
protected Composite createSelectionButtons(Composite composite) {
Composite buttonComposite= super.createSelectionButtons(composite);
GridLayout layout= new GridLayout();
buttonComposite.setLayout(layout);
createGetterSetterButtons(buttonComposite);
layout.marginHeight= 0;
layout.marginWidth= 0;
layout.numColumns= 1;
return buttonComposite;
}
/*
* @see org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog#createLinkControl(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createLinkControl(Composite composite) {
Link link= new Link(composite, SWT.WRAP);
link.setText(ActionMessages.AddGetterSetterAction_template_link_description);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openCodeTempatePage(CodeTemplateContextType.GETTERCOMMENT_ID);
}
});
link.setToolTipText(ActionMessages.AddGetterSetterAction_template_link_tooltip);
GridData gridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false);
gridData.widthHint= convertWidthInCharsToPixels(40); // only expand further if anyone else requires it
link.setLayoutData(gridData);
return link;
}
}
private static class GetterSetterEntry {
public final IField field;
public final boolean isGetter;
public final boolean isFinal;
GetterSetterEntry(IField field, boolean isGetterEntry, boolean isFinal) {
this.field= field;
this.isGetter= isGetterEntry;
this.isFinal= isFinal;
}
}
}