Java tutorial
/******************************************************************************* * This file is part of the PDT Extensions eclipse plugin. * * (c) Robert Gruendler <r.gruendler@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. ******************************************************************************/ package com.dubture.pdt.ui.actions; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.dltk.core.IField; import org.eclipse.dltk.core.IMember; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ISourceRange; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.core.SourceType; import org.eclipse.dltk.ui.DLTKPluginImages; import org.eclipse.dltk.ui.DLTKUIPlugin; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.Window; import org.eclipse.php.core.compiler.PHPFlags; import org.eclipse.php.internal.core.PHPCoreConstants; import org.eclipse.php.internal.core.PHPCorePlugin; import org.eclipse.php.internal.core.ast.nodes.ASTNode; import org.eclipse.php.internal.core.ast.nodes.ASTParser; import org.eclipse.php.internal.core.ast.nodes.Block; import org.eclipse.php.internal.core.ast.nodes.ClassDeclaration; import org.eclipse.php.internal.core.ast.nodes.Program; import org.eclipse.php.internal.core.ast.nodes.Statement; import org.eclipse.php.internal.core.format.FormatPreferencesSupport; import org.eclipse.php.internal.ui.actions.SelectionHandler; import org.eclipse.php.internal.ui.editor.PHPStructuredEditor; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.handlers.HandlerUtil; import org.eclipse.ui.texteditor.ITextEditor; import com.dubture.pdt.formatter.core.ast.Formatter; import com.dubture.pdt.ui.dialog.GetterSetterDialog; import com.dubture.pdt.ui.util.GetterSetterUtil; /** * * Generates getters for private fields. * * @author Robert Gruendler <r.gruendler@gmail.com> * */ @SuppressWarnings("restriction") public class GenerateGettersHandler extends SelectionHandler implements IHandler { private IEditorPart editorPart; private PHPStructuredEditor textEditor; private IDocument document; private Map options; private SourceType type; private String lineDelim; private boolean insertFirst = false; private IModelElement insertAfter = null; @SuppressWarnings("rawtypes") private static class GetterSetterContentProvider implements ITreeContentProvider { private Map fields; private static final Object[] EMPTY = new Object[0]; public GetterSetterContentProvider(Map fields) { this.fields = fields; } @Override public void dispose() { fields.clear(); fields = null; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { return fields.keySet().toArray(); } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof IField) { Object[] elems = (Object[]) fields.get(parentElement); for (Object elem : elems) { GetterSetterEntry entry = (GetterSetterEntry) elem; } return elems; } return EMPTY; } @Override public Object getParent(Object element) { if (element instanceof IMember) { return ((IMember) element).getDeclaringType(); } if (element instanceof GetterSetterEntry) return ((GetterSetterEntry) element).field; return null; } @Override public boolean hasChildren(Object element) { return getChildren(element).length > 0; } } private class GetterSetterLabelProvider extends LabelProvider { @Override public Image getImage(Object element) { if (element instanceof GetterSetterEntry) { return DLTKUIPlugin.getImageDescriptorRegistry().get(DLTKPluginImages.DESC_FIELD_PUBLIC); } else if (element instanceof IField) { return DLTKUIPlugin.getImageDescriptorRegistry().get(DLTKPluginImages.DESC_FIELD_PRIVATE); } return super.getImage(element); } @Override public String getText(Object element) { if (element instanceof GetterSetterEntry) { GetterSetterEntry entry = (GetterSetterEntry) element; return entry.getName(); } else if (element instanceof IField) { return GetterSetterUtil.getFieldName(((IField) element)); } return super.getText(element); } } protected Object exitMessage() { final Shell p = DLTKUIPlugin.getActiveWorkbenchShell(); MessageDialog.openInformation(p, "Getter/Setter generation unavailable", "No fields to generate getters/setters found."); return null; } @SuppressWarnings("rawtypes") @Override public Object execute(ExecutionEvent event) throws ExecutionException { IModelElement element = getCurrentModelElement(event); if (element == null) { return exitMessage(); } if (!(element instanceof SourceType)) { while (element.getParent() != null) { element = element.getParent(); if (element instanceof SourceType) { break; } } } if (element == null || !(element instanceof SourceType)) { return exitMessage(); } type = (SourceType) element; try { if (type.getFields().length == 0) { return exitMessage(); } initialize(event, element); Map fields = getFields(); final Shell p = DLTKUIPlugin.getActiveWorkbenchShell(); GetterSetterContentProvider cp = new GetterSetterContentProvider(fields); GetterSetterDialog dialog = new GetterSetterDialog(p, new GetterSetterLabelProvider(), cp, type); dialog.setContainerMode(true); dialog.setInput(type); dialog.setTitle("Generate Getters and Setters"); if (fields.size() == 0) { return exitMessage(); } if (dialog.open() == Window.OK) { List<GetterSetterEntry> entries = new ArrayList<GetterSetterEntry>(); Object[] dialogResult = dialog.getResult(); for (Object o : dialogResult) { if (o instanceof GetterSetterEntry) { entries.add((GetterSetterEntry) o); } } insertFirst = false; insertAfter = null; if (dialog.insertAsFirstMember()) insertFirst = true; else if (dialog.insertAsLastMember()) { } else insertAfter = dialog.getInsertionPoint(); generate(entries, dialog.getModifier(), dialog.doGenerateComments(), dialog.hasFluentInterface()); } } catch (Exception e) { e.printStackTrace(); } return null; } private void generate(final List<GetterSetterEntry> entries, final int modifier, final boolean generateComments, final boolean fluent) throws Exception { ISourceModule source = type.getSourceModule(); String name = type.getElementName().replace("$", ""); StringBuffer buffer = new StringBuffer(name); buffer.replace(0, 1, Character.toString(Character.toUpperCase(name.charAt(0)))); name = buffer.toString(); ASTParser parser = ASTParser.newParser(source); parser.setSource(document.get().toCharArray()); Program program = parser.createAST(new NullProgressMonitor()); // program.recordModifications(); // AST ast = program.getAST(); ISourceRange range = type.getSourceRange(); ASTNode node = program.getElementAt(range.getOffset()); if (!(node instanceof ClassDeclaration)) { return; } char indentChar = FormatPreferencesSupport.getInstance().getIndentationChar(document); String indent = String.valueOf(indentChar); ClassDeclaration clazz = (ClassDeclaration) node; Block body = clazz.getBody(); List<Statement> bodyStatements = body.statements(); int end = bodyStatements.get(bodyStatements.size() - 1).getEnd(); if (insertFirst) { end = bodyStatements.get(0).getStart() - 1; } else if (insertAfter != null) { boolean found = false; for (IMethod method : type.getMethods()) { if (method == insertAfter) { ISourceRange r = method.getSourceRange(); end = r.getOffset() + r.getLength(); found = true; } } if (!found) { for (IField field : type.getFields()) { ISourceRange r = field.getSourceRange(); end = r.getOffset() + r.getLength() + 1; } } } lineDelim = TextUtilities.getDefaultLineDelimiter(document); String methods = ""; int i = 0; for (GetterSetterEntry entry : entries) { String code = ""; if (!entry.isGetter) { code = GetterSetterUtil.getSetterStub(entry.field, entry.getIdentifier(), entry.getType(), generateComments, modifier, indent, fluent); } else { code = GetterSetterUtil.getGetterStub(entry.field, entry.getIdentifier(), generateComments, modifier, indent); } code = lineDelim + code; String formatted = indentPattern(code, indent, lineDelim); if (i++ == 0) { formatted = lineDelim + formatted; } methods += formatted; } document.replace(end, 0, methods); Formatter formatter = new Formatter(); Region region = new Region(end, methods.length()); formatter.format(document, region); } private String indentPattern(String originalPattern, String indentation, String lineDelim) { String delimPlusIndent = lineDelim + indentation; String indentedPattern = originalPattern.replaceAll(lineDelim, delimPlusIndent) + delimPlusIndent; return indentedPattern; } @SuppressWarnings({ "unchecked", "rawtypes" }) private void setupOptions() { options = new HashMap(PHPCorePlugin.getOptions()); IScopeContext[] contents = new IScopeContext[] { new ProjectScope(type.getScriptProject().getProject()), InstanceScope.INSTANCE, DefaultScope.INSTANCE }; for (int i = 0; i < contents.length; i++) { IScopeContext scopeContext = contents[i]; IEclipsePreferences inode = scopeContext.getNode(PHPCorePlugin.ID); if (inode != null) { if (!options.containsKey(PHPCoreConstants.FORMATTER_USE_TABS)) { String useTabs = inode.get(PHPCoreConstants.FORMATTER_USE_TABS, null); if (useTabs != null) { options.put(PHPCoreConstants.FORMATTER_USE_TABS, useTabs); } } if (!options.containsKey(PHPCoreConstants.FORMATTER_INDENTATION_SIZE)) { String size = inode.get(PHPCoreConstants.FORMATTER_INDENTATION_SIZE, null); if (size != null) { options.put(PHPCoreConstants.FORMATTER_INDENTATION_SIZE, size); } } } } } private void initialize(ExecutionEvent event, IModelElement element) throws InvalidElementException { editorPart = HandlerUtil.getActiveEditor(event); textEditor = null; if (editorPart instanceof PHPStructuredEditor) textEditor = (PHPStructuredEditor) editorPart; else { Object o = editorPart.getAdapter(ITextEditor.class); if (o != null) textEditor = (PHPStructuredEditor) o; } document = textEditor.getDocument(); setupOptions(); } @SuppressWarnings({ "rawtypes", "unchecked" }) private Map getFields() throws ModelException { IField[] fields = type.getFields(); Map result = new LinkedHashMap(); for (int i = 0; i < fields.length; i++) { IField field = fields[i]; int flags = field.getFlags(); if (PHPFlags.isStatic(flags) || PHPFlags.isConstant(flags)) { continue; } String name = field.getElementName().replace("$", ""); String getter = "get" + name.toLowerCase(); String setter = "set" + name.toLowerCase(); List l = new ArrayList(2); List<GetterSetterEntry> entries = new ArrayList<GetterSetterEntry>(); boolean getterExists = false; boolean setterExists = false; for (IMethod method : type.getMethods()) { String methodName = method.getElementName().toLowerCase(); if (methodName.startsWith("get")) { getterExists = methodName.equals(getter); } else if (methodName.startsWith("set")) { setterExists = methodName.equals(setter); } } if (!getterExists) { entries.add(new GetterSetterEntry(field, true)); } if (!setterExists) { entries.add(new GetterSetterEntry(field, false)); } if (!getterExists || !setterExists) { l.addAll(entries); } if (!l.isEmpty()) result.put(field, l.toArray(new GetterSetterEntry[l.size()])); } return result; } private class InvalidElementException extends Exception { private static final long serialVersionUID = 1L; } public static class GetterSetterEntry { public final IField field; public final boolean isGetter; private String name = null; private String identifier = null; private String type = null; private String raw = null; public GetterSetterEntry(IField field, boolean isGetterEntry) { this.field = field; this.isGetter = isGetterEntry; } public String getIdentifier() { if (identifier != null) return identifier; if (isGetter) return identifier = GetterSetterUtil.getGetterName(field); else return identifier = GetterSetterUtil.getSetterName(field); } public String getType() { if (type != null) return type; return type = GetterSetterUtil.getTypeReference(field); } public String getName() { if (name != null) return name; if (isGetter) { return name = String.format("%s()", getIdentifier()); } else { String elemName = field.getElementName(); String type = getType(); String param = ""; if (type != null && type != "") { param += type + " "; } param += elemName; return name = String.format("%s(%s)", getIdentifier(), param); } } public String getRawFieldName() { if (raw != null) return raw; return raw = field.getElementName().replace("$", ""); } } }