package bluej.stride.framedjava.elements;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;

import java.util.stream.Stream;

import bluej.debugger.gentype.ConstructorReflective;
import bluej.stride.framedjava.ast.FrameFragment;
import bluej.stride.framedjava.errors.SyntaxCodeError;
import bluej.stride.generic.AssistContentThreadSafe;
import bluej.stride.generic.InteractionManager;
import javafx.application.Platform;
import nu.xom.Element;
import threadchecker.OnThread;
import threadchecker.Tag;
import bluej.editor.moe.MoeSyntaxDocument;
import bluej.parser.ExpressionTypeInfo;
import bluej.parser.entity.EntityResolver;
import bluej.stride.framedjava.ast.JavaFragment;
import bluej.stride.framedjava.ast.JavaFragment.PosInSourceDoc;
import bluej.stride.framedjava.ast.JavaSource;
import bluej.stride.framedjava.ast.JavadocUnit;
import bluej.stride.framedjava.ast.NameDefSlotFragment;
import bluej.stride.framedjava.ast.SlotFragment;
import bluej.stride.framedjava.ast.TypeSlotFragment;
import bluej.stride.framedjava.frames.InterfaceFrame;
import bluej.stride.framedjava.frames.TopLevelFrame;
import bluej.stride.framedjava.slots.ExpressionSlot;
import bluej.stride.generic.Frame.ShowReason;
import bluej.utility.Utility;

public class InterfaceElement
extends DocumentContainerCodeElement implements TopLevelCodeElement{    
   public static final String ELEMENT = "interface";
   
   private final NameDefSlotFragment interfaceName;   
   
   private final List<TypeSlotFragment> extendsTypes;
   
   private JavadocUnit documentation;

   
| The package name (will not be null, but package name within may be blank | private final String packageName; private final List<ImportElement> imports;
| The list of fields in this class | private final List<CodeElement> fields;
| The list of methods in this class | private final List<CodeElement> methods; private final EntityResolver projectResolver; private InterfaceFrame frame;
| The curly brackets and interface keyword in the generated code (saved for mapping positions) | private final FrameFragment openingCurly = new FrameFragment(this.frame, this, "{"); private final FrameFragment closingCurly = new FrameFragment(this.frame, this, "}"); private JavaFragment interfaceKeyword;
| The generated Java code for this interface, used for doing code completion without | needing to always regenerate the document. | private DocAndPositions sourceDocument; private ExpressionSlot<?> sourceDocumentCompleting;
| A map of documents for given contents. This guards against race hazards, so | that we use the correct document for the given content, even when we are hopping | across threads and potentially generating several documents in a short space | of time, concurrent with looking up information in them. | | This cache does not have a size limit, but that shouldn't matter as it is per-instance | so the only potential differences in source code are down to which slot is being completed, | giving a limit on the number of documents we could generate for a given source version | (each InterfaceElement is immutable). | private final HashMap<String, DocAndPositions> documentCache = new HashMap<>(); public InterfaceElement(InterfaceFrame frame, EntityResolver projectResolver, NameDefSlotFragment interfaceName, List<TypeSlotFragment> extendsTypes, List<CodeElement> fields, List<CodeElement> methods, JavadocUnit documentation, String packageName, List<ImportElement> imports, boolean enabled) { this.frame = frame; this.interfaceName = interfaceName; this.extendsTypes = extendsTypes == null ? new ArrayList<>() : new ArrayList<>(extendsTypes); this.documentation = documentation != null ? documentation : new JavadocUnit(""); this.packageName = (packageName == null) ? "" : packageName; this.imports = new ArrayList<>(imports); this.fields = new ArrayList<>(fields); this.fields.forEach(field -> field.setParent(this)); this.methods = new ArrayList<>(methods); this.methods.forEach(method -> method.setParent(this)); this.enable = enabled; this.projectResolver = projectResolver; } public InterfaceElement(Element el, EntityResolver projectResolver, String packageName) { this.projectResolver = projectResolver; interfaceName = new NameDefSlotFragment(el.getAttributeValue("name")); Element javadocEL = el.getFirstChildElement("javadoc"); if (javadocEL != null) { documentation = new JavadocUnit(javadocEL); } else { documentation = new JavadocUnit(""); } extendsTypes = TopLevelCodeElement.xmlToTypeList(el, "extends", "extendstype", "type"); this.packageName = packageName; imports = Utility.mapList(TopLevelCodeElement.fillChildrenElements(this, el, "imports"), e -> (ImportElement)e); fields = TopLevelCodeElement.fillChildrenElements(this, el, "fields"); methods = TopLevelCodeElement.fillChildrenElements(this, el, "methods"); enable = Boolean.valueOf(el.getAttributeValue("enable")); }
| Creates an interface element with minimum information (when creating new interface from template name) | public InterfaceElement(EntityResolver entityResolver, String interfaceName, String packageName) { this(null, entityResolver, new NameDefSlotFragment(interfaceName), null, Collections.emptyList(), Collections.emptyList(), null, packageName, Collections.emptyList(), true); } @Override public ExpressionTypeInfo getCodeSuggestions(PosInSourceDoc pos, ExpressionSlot<?> completing) { MoeSyntaxDocument doc = getSourceDocument(completing); return doc.getParser().getExpressionType(pos.offset, getSourceDocument(completing)); } @Override public LocatableElement toXML() { LocatableElement interfaceEl = new LocatableElement(this, ELEMENT); interfaceEl.addAttributeCode("name", interfaceName); if (!extendsTypes.isEmpty()) { interfaceEl.appendChild( TopLevelCodeElement.typeListToXML( extendsTypes, "extends", "extendstype", "type")); } addEnableAttribute(interfaceEl); if (documentation != null) { interfaceEl.appendChild(documentation.toXML()); } appendCollection(interfaceEl, imports, "imports"); appendCollection(interfaceEl, fields, "fields"); appendCollection(interfaceEl, methods, "methods"); interfaceEl.addAttribute(TopLevelCodeElement.getStrideVersionAttribute()); return interfaceEl; } private void appendCollection(Element topEl, List<? extends CodeElement> collection, String name) { Element collectionEl = new Element(name); collection.forEach(element -> collectionEl.appendChild(element.toXML())); topEl.appendChild(collectionEl); } @Override @OnThread(Tag.FXPlatform) public JavaSource toJavaSource() { return getDAP(null).java; } @OnThread(Tag.FXPlatform) private JavaSource generateJavaSource() { List<JavaFragment> header = new ArrayList<>(); header.add(new FrameFragment(frame, this, "public ")); interfaceKeyword = new FrameFragment(frame, this, "interface "); Collections.addAll(header, interfaceKeyword, interfaceName); if (!extendsTypes.isEmpty()) { Collections.addAll(header, space(), f(frame, "extends"), space()); header.addAll(extendsTypes.stream().collect(Utility.intersperse(() -> f(frame, ", ")))); } JavaSource java = new JavaSource(null, header); java.prependJavadoc(documentation.getJavaCode()); java.prependLine(Arrays.asList((JavaFragment) f(frame, "")), null); Utility.backwards(CodeElement.toJavaCodes(imports)).forEach(imp -> java.prepend(imp)); java.prependLine(Collections.singletonList(f(frame, "import lang.stride.*;")), null); if (!packageName.equals("")) java.prependLine(Arrays.asList(f(frame, "package " + packageName + ";")), null); openingCurly.setFrame(frame); java.appendLine(Arrays.asList(openingCurly), null); fields.stream().filter(f -> f.isEnable()).forEach(f -> java.addIndented(f.toJavaSource())); methods.stream().filter(m -> m.isEnable()).forEach(m -> { java.appendLine(Arrays.asList((JavaFragment) f(frame, "")), null); java.addIndented(m.toJavaSource()); }); closingCurly.setFrame(frame); java.appendLine(Arrays.asList(closingCurly), null); return java; } @Override public InterfaceFrame createFrame(InteractionManager editor) { frame = new InterfaceFrame(editor, projectResolver, packageName, imports, documentation, interfaceName, extendsTypes, enable); fields.forEach(member -> frame.getfieldsCanvas().insertBlockAfter(member.createFrame(editor), null)); methods.forEach(member -> frame.getMethodsCanvas().insertBlockAfter(member.createFrame(editor), null)); return frame; } @Override public InterfaceFrame createTopLevelFrame(InteractionManager editor) { return createFrame(editor); } @Override public List getImports() { return Collections.unmodifiableList(imports); } @Override public String getName() { return interfaceName.getContent(); } public List getExtends() { return Utility.mapList(extendsTypes, TypeSlotFragment::getContent); } public List getMethods() { return methods; } public List getFields() { return fields; } @Override public List childrenUpTo(CodeElement c) { List<CodeElement> joined = new ArrayList<>(); joined.addAll(fields); joined.addAll(methods); return joined.subList(0, joined.indexOf(c)); } @Override public String getStylePrefix() { return "interface-"; } @Override public EntityResolver getResolver() { return getSourceDocument(null).getParser(); } @Override public TopLevelFrame getFrame() { return frame; } @Override public InteractionManager getEditor() { return frame.getEditor(); } @Override public void show(ShowReason reason) { frame.show(reason); } @OnThread(Tag.FXPlatform) private MoeSyntaxDocument getSourceDocument(ExpressionSlot completing) { return getDAP(completing).getDocument(projectResolver); } @OnThread(Tag.FXPlatform) private synchronized DocAndPositions getDAP(ExpressionSlot completing) { if (sourceDocument == null || sourceDocumentCompleting != completing) { IdentityHashMap<JavaFragment, Integer> positions = new IdentityHashMap<>(); sourceDocumentCompleting = completing; JavaSource java = generateJavaSource(); String src = java.toMemoryJavaCodeString(positions, completing); if (documentCache.containsKey(src)) { sourceDocument = documentCache.get(src); sourceDocument.fragmentPositions.putAll(positions); } else { sourceDocument = new DocAndPositions(src, java, positions); documentCache.put(src, sourceDocument); } } return sourceDocument; } @Override public Stream streamContained() { Stream<CodeElement> result = streamContained(fields); return Stream.concat(result, streamContained(methods)); } @Override protected Stream getDirectSlotFragments() { return Stream.<SlotFragment>concat(Stream.<SlotFragment>of(interfaceName), extendsTypes.stream()).filter(s -> s != null); } @Override public void updateSourcePositions() { Platform.runLater(() -> getSourceDocument(null)); } @Override public List getSuperConstructors() { return Collections.emptyList(); } @Override public List getThisConstructors() { return Collections.emptyList(); } private static class DocAndPositions { public final JavaSource java; public final IdentityHashMap<JavaFragment, Integer> fragmentPositions; private String src; private MoeSyntaxDocument document; public DocAndPositions(String src, JavaSource java, IdentityHashMap<JavaFragment, Integer> fragmentPositions) { this.src = src; this.java = java; this.fragmentPositions = fragmentPositions; } @OnThread(Tag.FXPlatform) public MoeSyntaxDocument getDocument(EntityResolver projectResolver) { if (document == null) { document = new MoeSyntaxDocument(projectResolver); document.insertString(0, src); document.enableParser(true); } return document; } } @Override public Stream findEarlyErrors() { return findEarlyErrors(toXML().buildLocationMap()); } }
top, use, map, class InterfaceElement

.   InterfaceElement
.   InterfaceElement
.   InterfaceElement
.   getCodeSuggestions
.   toXML
.   appendCollection
.   toJavaSource
.   generateJavaSource
.   createFrame
.   createTopLevelFrame
.   getImports
.   getName
.   getExtends
.   getMethods
.   getFields
.   childrenUpTo
.   getStylePrefix
.   getResolver
.   getFrame
.   getEditor
.   show
.   getSourceDocument
.   getDAP
.   streamContained
.   getDirectSlotFragments
.   updateSourcePositions
.   getSuperConstructors
.   getThisConstructors

top, use, map, class DocAndPositions

.   DocAndPositions
.   getDocument
.   findEarlyErrors




478 neLoCode + 15 LoComm