package bluej.stride.framedjava.elements;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import bluej.stride.framedjava.ast.JavaFragment;
import bluej.stride.generic.InteractionManager;
import bluej.utility.Utility;
import nu.xom.Element;
import threadchecker.OnThread;
import threadchecker.Tag;
import bluej.debugger.gentype.Reflective;
import bluej.stride.framedjava.ast.AccessPermission;
import bluej.stride.framedjava.ast.AccessPermissionFragment;
import bluej.stride.framedjava.ast.HighlightedBreakpoint;
import bluej.stride.framedjava.ast.JavaSingleLineDebugHandler;
import bluej.stride.framedjava.ast.JavadocUnit;
import bluej.stride.framedjava.ast.Loader;
import bluej.stride.framedjava.ast.NameDefSlotFragment;
import bluej.stride.framedjava.ast.ParamFragment;
import bluej.stride.framedjava.ast.ThrowsTypeFragment;
import bluej.stride.framedjava.ast.TypeSlotFragment;
import bluej.stride.framedjava.frames.DebugInfo;
import bluej.stride.framedjava.frames.MethodFrameWithBody;


| A parent class which is shared between ConstructorElement and NormalMethodElement. | These two items have a lot in comment, which is collected here. | public abstract class MethodWithBodyElement extends DocumentContainerCodeElement implements JavaSingleLineDebugHandler{ protected final List<ParamFragment> params; protected final List<ThrowsTypeFragment> throwsTypes; protected final List<CodeElement> contents; protected MethodFrameWithBody<?> frame; protected AccessPermissionFragment access;
| Constructor when generated from the GUI | public MethodWithBodyElement(MethodFrameWithBody<?> frame, AccessPermissionFragment access, List<ParamFragment> params, List<ThrowsTypeFragment> throwsTypes, List<CodeElement> contents, JavadocUnit documentation, boolean enabled) { this.frame = frame; this.access = access; this.params = params; this.throwsTypes = throwsTypes; this.contents = contents; this.documentation = documentation; for (CodeElement c : this.contents) { c.setParent(this); } this.enable = enabled; if (this.documentation == null) { this.documentation = new JavadocUnit(""); } }
| Constructor when loaded from file/clipboard | public MethodWithBodyElement(Element el) { access = new AccessPermissionFragment(AccessPermission.fromString(el.getAttributeValue("access"))); params = new ArrayList<>(); this.throwsTypes = new ArrayList<>(); contents = new ArrayList<>(); for (int i = 0; i < el.getChildElements().size(); i++) { final Element child = el.getChildElements().get(i); switch (child.getLocalName()) { case "params": for (int j = 0; j < child.getChildElements().size(); j++) { params.add(new ParamFragment(child.getChildElements().get(j))); } break; case "throws": for (int j = 0; j < child.getChildElements().size(); j++) { throwsTypes.add(new ThrowsTypeFragment(child.getChildElements().get(j))); } break; case "body": for (int j = 0; j < child.getChildElements().size(); j++) { CodeElement member = Loader.loadElement(child.getChildElements().get(j)); contents.add(member); member.setParent(this); } break; case "javadoc": documentation = new JavadocUnit(child); break; } } if (documentation == null) { documentation = new JavadocUnit(""); } enable = Boolean.valueOf(el.getAttributeValue("enable")); }
| Constructor when automatically generated, e.g. by Save the World in Greenfoot | public MethodWithBodyElement(String access, List<Entry<String,String>> params, List<CodeElement> contents, String documentation) { this.access = new AccessPermissionFragment(AccessPermission.fromString(access)); this.contents = new ArrayList<>(contents); this.documentation = new JavadocUnit(documentation); this.throwsTypes = new ArrayList<>(); this.params = new ArrayList<>(); if (params != null ) { for (Entry<String, String> entry : params) { this.params.add(new ParamFragment(new TypeSlotFragment(entry.getKey(), entry.getKey()), new NameDefSlotFragment(entry.getValue()))); } } }
| Helper method for subclasses when generating XML: add access attribute to given XML | protected void accessToXML(LocatableElement methodEl) { if (access != null) { methodEl.addAttributeAccess("access", access); } }
| Helper method for subclasses when generating XML: add params child element to given XML | protected void paramsToXML(Element methodEl) { Element paramsEl = new Element("params"); for (ParamFragment param : params) { paramsEl.appendChild(param.toXML()); } methodEl.appendChild(paramsEl); }
| Helper method for subclasses when generating XML: add throws child element to given XML | protected void throwsToXML(Element methodEl) { Element throwsEl = new Element("throws"); for (ThrowsTypeFragment t : throwsTypes) { throwsEl.appendChild(t.toXML()); } methodEl.appendChild(throwsEl); }
| Helper method for subclasses when generating XML: add body child element to given XML | protected void bodyToXML(Element methodEl) { Element bodyEl = new Element("body"); for (CodeElement c : contents) { bodyEl.appendChild(c.toXML()); } methodEl.appendChild(bodyEl); }
| Helper method for subclasses when generating Java: Turn throws declaration into Java | protected List throwsToJava() { if (throwsTypes.isEmpty()) return Collections.emptyList(); ArrayList<JavaFragment> typesAndCommas = throwsTypes.stream().map(ThrowsTypeFragment::getJavaSource).collect(Utility.intersperse(() -> (JavaFragment)f(null, ", "))); typesAndCommas.add(0, space()); typesAndCommas.add(0, f(frame, "throws")); typesAndCommas.add(0, space()); return typesAndCommas; }
| Helper method for subclasses when generating a Frame (in our frame field) | @OnThread(Tag.FX) protected void setupFrame(InteractionManager editor) { frame.setAccess(access.getValue()); frame.setDocumentation(documentation.toString()); params.forEach(item -> frame.getParamsPane().addFormal(item.getParamType(), item.getParamName())); contents.forEach(c -> frame.getCanvas().insertBlockAfter(c.createFrame(editor), null)); throwsTypes.forEach(t -> frame.addThrows(t.getType())); } @Override public List getDeclaredVariablesWithin(CodeElement child) { List<LocalParamInfo> vars = new ArrayList<>(); params.forEach(param -> vars.add(new LocalParamInfo(param.getParamType().getContent(), param.getParamName().getContent(), true, this))); return vars; } @Override public List childrenUpTo(CodeElement c) { return contents.subList(0, contents.indexOf(c)); } @Override public HighlightedBreakpoint showDebugBefore(DebugInfo debug) { return frame.showDebugBefore(debug); } @Override public MethodWithBodyElement getMethodElement() { return this; } public List getContents() { return contents; } public abstract String getType(); @Override public Stream streamContained() { return streamContained(contents); } @OnThread(Tag.FXPlatform) public List getQualifiedParamTypes(ClassElement topLevel) { return params.stream().map(p -> { TypeSlotFragment paramType = p.getParamType(); Reflective qualifyType = topLevel.qualifyType(paramType.getContent(), paramType.getPosInSourceDoc()); if (qualifyType == null) return paramType.getContent(); return qualifyType.getName(); } ).collect(Collectors.toList()); } public AccessPermission getAccessPermission() { return access.getValue(); } public List getThrowsTypes() { return Utility.mapList(throwsTypes, ThrowsTypeFragment::getType); } public List getParams() { return params; } }
top, use, map, abstract class MethodWithBodyElement

.   MethodWithBodyElement
.   MethodWithBodyElement
.   MethodWithBodyElement
.   accessToXML
.   paramsToXML
.   throwsToXML
.   bodyToXML
.   throwsToJava
.   setupFrame
.   getDeclaredVariablesWithin
.   childrenUpTo
.   showDebugBefore
.   getMethodElement
.   getContents
.   getType
.   streamContained
.   getQualifiedParamTypes
.   getAccessPermission
.   getThrowsTypes
.   getParams




337 neLoCode + 11 LoComm