package bluej.pkgmgr.target;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.TypeVariable;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import javax.swing.SwingUtilities;

import bluej.Config;
import bluej.collect.DataCollector;
import bluej.collect.DiagnosticWithShown;
import bluej.collect.StrideEditReason;
import bluej.compiler.CompileInputFile;
import bluej.compiler.CompileReason;
import bluej.compiler.CompileType;
import bluej.compiler.Diagnostic;
import bluej.debugger.Debugger;
import bluej.debugger.DebuggerClass;
import bluej.debugger.DebuggerObject;
import bluej.debugger.DebuggerResult;
import bluej.debugger.RunOnThread;
import bluej.debugger.gentype.Reflective;
import bluej.debugmgr.objectbench.InvokeListener;
import bluej.editor.Editor;
import bluej.editor.EditorManager;
import bluej.editor.TextEditor;
import bluej.editor.stride.FrameCatalogue;
import bluej.editor.stride.FrameEditor;
import bluej.extensions.BClass;
import bluej.extensions.BClassTarget;
import bluej.extensions.BDependency;
import bluej.extensions.ExtensionBridge;
import bluej.extensions.SourceType;
import bluej.extensions.event.ClassEvent;
import bluej.extensions.event.ClassTargetEvent;
import bluej.extmgr.ClassExtensionMenu;
import bluej.extmgr.ExtensionsManager;
import bluej.extmgr.FXMenuManager;
import bluej.parser.ParseFailure;
import bluej.parser.entity.EntityResolver;
import bluej.parser.entity.PackageResolver;
import bluej.parser.entity.ParsedReflective;
import bluej.parser.nodes.ParsedCUNode;
import bluej.parser.nodes.ParsedTypeNode;
import bluej.parser.symtab.ClassInfo;
import bluej.parser.symtab.Selection;
import bluej.pkgmgr.DuplicateClassDialog;
import bluej.pkgmgr.JavadocResolver;
import bluej.pkgmgr.Package;
import bluej.pkgmgr.PackageEditor;
import bluej.pkgmgr.PkgMgrFrame;
import bluej.pkgmgr.Project;
import bluej.pkgmgr.ProjectUtils;
import bluej.pkgmgr.SourceInfo;
import bluej.pkgmgr.dependency.Dependency;
import bluej.pkgmgr.dependency.ExtendsDependency;
import bluej.pkgmgr.dependency.ImplementsDependency;
import bluej.pkgmgr.dependency.UsesDependency;
import bluej.pkgmgr.target.role.AbstractClassRole;
import bluej.pkgmgr.target.role.ClassRole;
import bluej.pkgmgr.target.role.EnumClassRole;
import bluej.pkgmgr.target.role.InterfaceClassRole;
import bluej.pkgmgr.target.role.StdClassRole;
import bluej.pkgmgr.target.role.UnitTestClassRole;
import bluej.stride.framedjava.ast.Loader;
import bluej.stride.framedjava.ast.Parser;
import bluej.stride.framedjava.convert.ConversionWarning;
import bluej.stride.framedjava.convert.ConvertResultDialog;
import bluej.stride.framedjava.elements.CodeElement;
import bluej.stride.framedjava.elements.TopLevelCodeElement;
import bluej.stride.generic.Frame;
import bluej.utility.Debug;
import bluej.utility.DialogManager;
import bluej.utility.FileEditor;
import bluej.utility.FileUtility;
import bluej.utility.JavaNames;
import bluej.utility.JavaReflective;
import bluej.utility.JavaUtils;
import bluej.utility.Utility;
import bluej.utility.javafx.FXPlatformConsumer;
import bluej.utility.javafx.FXPlatformRunnable;
import bluej.utility.javafx.FXPlatformSupplier;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.ResizableCanvas;
import bluej.views.ConstructorView;
import bluej.views.MethodView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.stage.Window;
import threadchecker.OnThread;
import threadchecker.Tag;


| A class target in a package, i.e. a target that is a class file built from | Java source code | | @author Michael Cahill | @author Michael Kolling | @author Bruce Quig | @OnThread(Tag.FXPlatform) public class ClassTarget extends DependentTarget implements InvokeListener{ final static int MIN_WIDTH = 60; final static int MIN_HEIGHT = 30; private final static String editStr = Config.getString("pkgmgr.classmenu.edit"); private final static String compileStr = Config.getString("pkgmgr.classmenu.compile"); private final static String inspectStr = Config.getString("pkgmgr.classmenu.inspect"); private final static String removeStr = Config.getString("pkgmgr.classmenu.remove"); private final static String convertToJavaStr = Config.getString("pkgmgr.classmenu.convertToJava"); private final static String convertToStrideStr = Config.getString("pkgmgr.classmenu.convertToStride"); private final static String duplicateClassStr = Config.getString("pkgmgr.classmenu.duplicate"); private final static String createTestStr = Config.getString("pkgmgr.classmenu.createTest"); private final static String launchFXStr = Config.getString("pkgmgr.classmenu.launchFX"); private static final String STEREOTYPE_OPEN = "\u00AB"; private static final String STEREOTYPE_CLOSE = "\u00BB"; private static final double RESIZE_CORNER_GAP = 4; private static String TEMP_FILE_EXTENSION = "-temp"; private ClassRole role = new StdClassRole(); private boolean openWithInterface = false; private SourceInfo sourceInfo = new SourceInfo(); private boolean isAbstract; private Optional<Boolean> isNaviviewExpanded = Optional.empty(); private final List<Integer> cachedBreakpoints = new ArrayList<>(); private boolean analysing = false; private boolean compilationInvalid = false; private boolean isMoveable = true; private SourceType sourceAvailable; private boolean hasBeenOpened = false; private String typeParameters = ""; private Map<String,String> properties = new HashMap<String,String>(); private boolean recordedAsOpen = false; private boolean visible = true; public static final String MENU_STYLE_INBUILT = "class-action-inbuilt"; private static String[] pseudos; @OnThread(Tag.FX) private ResizableCanvas canvas; private Label stereotypeLabel; private boolean isFront = true; @OnThread(Tag.FX) private static Image greyStripeImage; @OnThread(Tag.FX) private static Image redStripeImage; private static final int GREY_STRIPE_SEPARATION = 12; private static final int RED_STRIPE_SEPARATION = 16; private static final int STRIPE_THICKNESS = 3; @OnThread(Tag.FX) private static final Color RED_STRIPE = Color.rgb(170, 80, 60); @OnThread(Tag.FX) private static final Color GREY_STRIPE = Color.rgb(158, 139, 116); private boolean showingInterface; private boolean drawingExtends = false; private Label nameLabel; private Label noSourceLabel;
| Create a new class target in package 'pkg'. | | @param pkg Description of the Parameter | @param baseName Description of the Parameter | public ClassTarget(Package pkg, String baseName) { this(pkg, baseName, null); }
| Create a new class target in package 'pkg'. | | @param pkg Description of the Parameter | @param baseName Description of the Parameter | @param template Description of the Parameter | public ClassTarget(Package pkg, String baseName, String template) { super(pkg, baseName); if (pseudos == null) { pseudos = Utility.mapList(Arrays.<Class<? extends ClassRole>>asList(StdClassRole.class, UnitTestClassRole.class, AbstractClassRole.class, InterfaceClassRole.class, EnumClassRole.class), ClassTarget::pseudoFor).toArray(new String[0]); } JavaFXUtil.addStyleClass(pane, "class-target"); JavaFXUtil.addStyleClass(pane, "class-target-id-" + baseName); nameLabel = new Label(baseName); JavaFXUtil.addStyleClass(nameLabel, "class-target-name"); nameLabel.setMaxWidth(9999.0); stereotypeLabel = new Label(); stereotypeLabel.setMaxWidth(9999.0); stereotypeLabel.visibleProperty().bind(stereotypeLabel.textProperty().isNotEmpty()); stereotypeLabel.managedProperty().bind(stereotypeLabel.textProperty().isNotEmpty()); JavaFXUtil.addStyleClass(stereotypeLabel, "class-target-extra"); pane.setTop(new VBox(stereotypeLabel, nameLabel)); canvas = new ResizableCanvas() { @Override @OnThread(value = Tag.FXPlatform, ignoreParent = true) public void resize(double width, double height) { super.resize(width, height); redraw(); } }; pane.setCenter(canvas); noSourceLabel = new Label(""); StackPane stackPane = new StackPane(pane.getCenter(), noSourceLabel); StackPane.setAlignment(noSourceLabel, Pos.TOP_CENTER); StackPane.setAlignment(canvas, Pos.CENTER); pane.setCenter(stackPane); calcSourceAvailable(); if (template != null) { if (template.startsWith("unittest")) { setRole(new UnitTestClassRole(true)); } else if (template.startsWith("abstract")) { setRole(new AbstractClassRole()); } else if (template.startsWith("interface")) { setRole(new InterfaceClassRole()); } else if (template.startsWith("enum")) { setRole(new EnumClassRole()); } else { setRole(new StdClassRole()); } } JavaFXUtil.addChangeListener(canvas.sceneProperty(), scene -> { JavaFXUtil.runNowOrLater(() -> { nameLabel.applyCss(); updateSize(); }); }); }
| Check whether the class has source, and of what type. | private void calcSourceAvailable() { if (getFrameSourceFile().canRead()) { sourceAvailable = SourceType.Stride; noSourceLabel.setText(""); } else if (getJavaSourceFile().canRead()) { sourceAvailable = SourceType.Java; noSourceLabel.setText(""); } else { sourceAvailable = SourceType.NONE; setState(State.COMPILED); noSourceLabel.setText("(" + Config.getString("classTarget.noSource") + ")"); } } @OnThread(Tag.SwingIsFX) private BClass singleBClass; @OnThread(Tag.SwingIsFX) private BClassTarget singleBClassTarget; | Return the extensions BProject associated with this Project. | There should be only one BProject object associated with each Project. | @return the BProject associated with this Project. | @OnThread(Tag.SwingIsFX) public final BClass getBClass() { if ( singleBClass == null ) { singleBClass = ExtensionBridge.newBClass(this); } return singleBClass; }
| Returns the {}link BClassTarget} associated with this {}link ClassTarget}. | There should be only one {}link BClassTarget} object associated with | each {}link ClassTarget}. | | @return The {}link BClassTarget} associated with this {}link ClassTarget}. | @OnThread(Tag.SwingIsFX) public final BClassTarget getBClassTarget() { if (singleBClassTarget == null) { singleBClassTarget = ExtensionBridge.newBClassTarget(this); } return singleBClassTarget; }
| Return the target's name, including the package name. eg. | bluej.pkgmgr.Target | | @return The qualifiedName value | @OnThread(Tag.Any) public String getQualifiedName() { return getPackage().getQualifiedName(getBaseName()); }
| Return the target's base name (ie the name without the package name). eg. | Target | | @return The baseName value | @OnThread(Tag.Any) public String getBaseName() { return getIdentifierName(); }
| Return information about the source of this class. | | @return The source info object. | public SourceInfo getSourceInfo() { return sourceInfo; }
| Get a reflective for the type represented by this target. | | @return A suitable reflective, or null. | public Reflective getTypeReflective() { if (isCompiled()) { Class<?> cl = getPackage().loadClass(getQualifiedName()); if (cl != null) { return new JavaReflective(cl); } else { return null; } } ParsedCUNode node = null; if (getEditor() != null) { TextEditor textEditor = editor.assumeText(); if (textEditor != null) { node = textEditor.getParsedNode(); } } if (node != null) { ParsedTypeNode ptn = (ParsedTypeNode) node.getTypeNode(getBaseName()); if (ptn != null) { return new ParsedReflective(ptn); } } return null; }
| Returns the text which the target is displaying as its label. For normal | classes this is just the identifier name. For generic classes the generic | parameters are shown as well | | @return The displayName value | @Override public String getDisplayName() { return getBaseName() + getTypeParameters(); }
| Returns the type parameters for a generic class as declared in the source | file. | | @return The typeParameters value | private String getTypeParameters() { return typeParameters; }
| Change the state of this target. The target will be repainted to show the | new state. | | @param newState The new state value | @Override public void setState(State newState) { if (getState() != newState) { String qualifiedName = getQualifiedName(); Project proj = getPackage().getProject(); proj.removeInspectorInstance(qualifiedName); if (newState == State.COMPILED) { if (editor != null) { editor.reInitBreakpoints(); } } ClassEvent event = new ClassEvent(ClassEvent.STATE_CHANGED, getPackage(), getBClass(), newState == State.COMPILED, newState == State.HAS_ERROR); ExtensionsManager.getInstance().delegateEvent(event); super.setState(newState); } }
| Compilation of the class represented by this target has begun. | | @param compilationSequence compilation sequence identifier which can be used to associate | related compilation events. | public void markCompiling(int compilationSequence) { compilationInvalid = (editor != null) ? editor.isModified() : false; if (getState() == State.HAS_ERROR) { setState(State.NEEDS_COMPILE); } if (getSourceType() == SourceType.Stride) { getEditor(); } if (editor != null) { if (editor.compileStarted(compilationSequence)) { setState(State.HAS_ERROR); } } }
| Return the role object for this class target. | | @return The role value | public ClassRole getRole() { return role; }
| Set the role for this class target. | | <p>Avoids changing over the role object if the new one is of the same type. | | @param newRole The new role value | protected final void setRole(ClassRole newRole) { if (role == null || role.getRoleName() != newRole.getRoleName()) { role = newRole; String select = pseudoFor(role.getClass()); String stereotype = role.getStereotypeLabel(); public defVis boolean shouldBeFront = role == null || !(role instanceof UnitTestClassRole); isFront = shouldBeFront; JavaFXUtil.selectPseudoClass(pane, Arrays.asList(pseudos).indexOf(select), pseudos); if (stereotype != null) stereotypeLabel.setText(STEREOTYPE_OPEN + stereotype + STEREOTYPE_CLOSE); else{ stereotypeLabel.setText(""); } } } @OnThread(Tag.Any) private static String pseudoFor(Class<? extends ClassRole> aClass) { String name = aClass.getSimpleName(); if (name.endsWith("ClassRole")) name = name.substring(0, name.length() - "ClassRole".length()); return "bj-" + name.toLowerCase(); }
| Test if a given class is a Junit 4 test class. | | <p>In Junit4, test classes can be of any type. | The only way to test is to check if it has one of the following annotations: | @Before, @Test or @After | | @param cl class to test | @SuppressWarnings("unchecked") public static boolean isJunit4TestClass(Class<?> cl) { ClassLoader clLoader = cl.getClassLoader(); try { Class<? extends Annotation> beforeClass = (Class<? extends Annotation>) Class.forName("org.junit.Before", false, clLoader); Class<? extends Annotation> afterClass = (Class<? extends Annotation>) Class.forName("org.junit.After", false, clLoader); Class<? extends Annotation> testClass = (Class<? extends Annotation>) Class.forName("org.junit.Test", false, clLoader); Method[] methods = cl.getDeclaredMethods(); for (int i=0; i<methods.length; i++) { if (methods[i].getAnnotation(beforeClass) != null) { return true; } if (methods[i].getAnnotation(afterClass) != null) { return true; } if (methods[i].getAnnotation(testClass) != null) { return true; } } } catch (ClassNotFoundException cnfe) { } catch (LinkageError le) { } return false; }
| Use a variety of tests to determine what our role is. | | <p>All tests must be very quick and should not rely on any significant | computation (ie. reparsing). If computation is required, the existing | role will do for the time being. | | @param cl Description of the Parameter | public void determineRole(Class<?> cl) { if (cl != null) { isAbstract = Modifier.isAbstract(cl.getModifiers()); ClassLoader clLoader = cl.getClassLoader(); Class<?> junitClass = null; if (clLoader != null) { try { junitClass = clLoader.loadClass("junit.framework.TestCase"); } catch (ClassNotFoundException cnfe) { } catch (LinkageError le) { } } if (junitClass == null) { junitClass = junit.framework.TestCase.class; } if (junitClass.isAssignableFrom(cl)) { setRole(new UnitTestClassRole(false)); } else if (Modifier.isInterface(cl.getModifiers())) { setRole(new InterfaceClassRole()); } else if (JavaUtils.getJavaUtils().isEnum(cl)) { setRole(new EnumClassRole()); } else if (isAbstract) { setRole(new AbstractClassRole()); } else if (isJunit4TestClass(cl)) { setRole(new UnitTestClassRole(true)); } else { setRole(new StdClassRole()); } } else { isAbstract = false; ClassInfo classInfo = sourceInfo.getInfoIfAvailable(); if (classInfo != null) { if (classInfo.isUnitTest()) { setRole(new UnitTestClassRole(false)); } else if (classInfo.isInterface()) { setRole(new InterfaceClassRole()); } else if (classInfo.isEnum()) { setRole(new EnumClassRole()); } else if (classInfo.isAbstract()) { setRole(new AbstractClassRole()); } else { if (!(role instanceof UnitTestClassRole)) { setRole(new StdClassRole()); } } } } }
| Load existing information about this class target | | @param props the properties object to read | @param prefix an internal name used for this target to identify its | properties in a properties file used by multiple targets. | @exception NumberFormatException Description of the Exception | @Override public void load(Properties props, String prefix) { super.load(props, prefix); String type = props.getProperty(prefix + ".type"); String intf = props.getProperty(prefix + ".showInterface"); openWithInterface = Boolean.valueOf(intf).booleanValue(); if (UnitTestClassRole.UNITTEST_ROLE_NAME.equals(type)) { setRole(new UnitTestClassRole(false)); } else if (UnitTestClassRole.UNITTEST_ROLE_NAME_JUNIT4.equals(type)) { setRole(new UnitTestClassRole(true)); } else if (AbstractClassRole.ABSTRACT_ROLE_NAME.equals(type)) { setRole(new AbstractClassRole()); } else if (InterfaceClassRole.INTERFACE_ROLE_NAME.equals(type)) { setRole(new InterfaceClassRole()); } else if (EnumClassRole.ENUM_ROLE_NAME.equals(type)) { setRole(new EnumClassRole()); } getRole().load(props, prefix); String value=props.getProperty(prefix + ".naviview.expanded"); if (value!=null){ setNaviviewExpanded(Boolean.parseBoolean(value)); setProperty(NAVIVIEW_EXPANDED_PROPERTY, String.valueOf(value)); } typeParameters = ""; cachedBreakpoints.clear(); try { for (int i = 0; ; i++) { String s = props.getProperty(prefix + ".breakpoint." + Integer.toString(i), ""); if (s != null && !s.isEmpty()) { cachedBreakpoints.add(Integer.parseInt(s)); } else{ break; } } } catch (NumberFormatException e) { Debug.reportError("Error parsing breakpoint line number", e); } }
| Save information about this class target | | @param props the properties object to save to | @param prefix an internal name used for this target to identify its | properties in a properties file used by multiple targets. | @Override public void save(Properties props, String prefix) { super.save(props, prefix); if (getRole().getRoleName() != null) { props.put(prefix + ".type", getRole().getRoleName()); } boolean intf; openWithInterface = showingInterface; intf = openWithInterface; if (getProperty(NAVIVIEW_EXPANDED_PROPERTY) != null) { props.put(prefix + ".naviview.expanded", String.valueOf(getProperty(NAVIVIEW_EXPANDED_PROPERTY))); } else if (isNaviviewExpanded.isPresent()) { props.put(prefix + ".naviview.expanded", String.valueOf(isNaviviewExpanded())); } props.put(prefix + ".showInterface", Boolean.valueOf(intf).toString()); List<Integer> breakpoints; if (editor != null && editor instanceof FrameEditor) { breakpoints = ((FrameEditor)editor).getBreakpoints(); } else { breakpoints = cachedBreakpoints; } for (int i = 0; i < breakpoints.size(); i++) { props.put(prefix + ".breakpoint." + i, breakpoints.get(i).toString()); } getRole().save(props, 0, prefix); }
| Notification that the source file may have been updated, and so we should | reload. | public void reload() { calcSourceAvailable(); if (sourceAvailable != SourceType.NONE) { if (editor != null) { editor.reloadFile(); } else { analyseSource(); } } }
| Check if the compiled class and the source are up to date. | (Specifically, check if recompilation is not needed. This will | always be considered true if the target has no source). | | @return true if they are in sync (or there is no source); otherwise false. | public boolean upToDate() { File src = getSourceFile(); File clss = getClassFile(); if (sourceAvailable == SourceType.NONE) { return true; } if (!clss.exists() || (src.exists() && (src.lastModified() > clss.lastModified()))) { return false; } return true; }
| Checks if the source file was modified in the future, and if so, set the modification time | to now. | public void fixSourceModificationDate() { if (sourceAvailable == SourceType.NONE) { return; } File src = getSourceFile(); long now = Instant.now().toEpochMilli(); if (src.exists() && (src.lastModified() > now + 1000)) { src.setLastModified(now); if (editor != null) { editor.setLastModified(src.lastModified()); } } }
| Mark this class as modified, and mark all dependent classes too | public void invalidate() { compilationInvalid = true; if (hasSourceCode()) { markModified(); } for (Dependency d : dependents()) { ClassTarget dependent = (ClassTarget) d.getFrom(); if (dependent.isCompiled() && dependent.hasSourceCode()) { dependent.invalidate(); } } }
| Verify whether this class target is an interface class | | @return true if class target is an interface class, else returns false | public boolean isInterface() { return (getRole() instanceof InterfaceClassRole); }
| Verify whether this class target is an unit test class | | @return true if class target is a unit test class, else returns false | public boolean isUnitTest() { return (getRole() instanceof UnitTestClassRole); }
| Verify whether this class target represents an Enum | | @return true if class target represents an Enum, else false | public boolean isEnum() { return (getRole() instanceof EnumClassRole); }
| Check whether this class target represents an abstract class. This | can be true regardless of the role (unit test, applet, standard class). | | The return is only valid if isCompiled() is true. | public boolean isAbstract() { return isAbstract; } | Tell whether we have access to the source for this class. | | @return Description of the Return Value | public boolean hasSourceCode() { return sourceAvailable != SourceType.NONE; } public SourceType getSourceType() { return sourceAvailable; }
| @return the name of the Java file this target corresponds to. In the case of a Stride target this is | the file generated during compilation. | public File getJavaSourceFile() { return new File(getPackage().getPath(), getBaseName() + "." + SourceType.Java.toString().toLowerCase()); }
| @return the name of the Stride file this target corresponds to. This is only valid for Stride targets. | public File getFrameSourceFile() { return new File(getPackage().getPath(), getBaseName() + "." + SourceType.Stride.toString().toLowerCase()); } @SuppressWarnings("incomplete-switch") @Override public File getSourceFile() { switch (sourceAvailable) { case Java: return getJavaSourceFile(); case Stride: return getFrameSourceFile(); } return null; } public boolean isVisible() { return visible; }
| Mark the class as having compiled, either successfully or not. | public void markCompiled(boolean successful, CompileType compileType) { if (compilationInvalid) { editor.compileFinished(successful, false); return; } if (successful && compileType.keepClasses()) { fixSourceModificationDate(); boolean newCompiledState = upToDate(); newCompiledState &= !hasKnownError(); if (newCompiledState) { setState(State.COMPILED); } } if (editor != null) { editor.compileFinished(successful, compileType.keepClasses()); if (isCompiled()) { editor.setCompiled(true); } } } public static class SourceFileInfo { public final File file; public final SourceType sourceType; public SourceFileInfo(File file, SourceType sourceType) { this.file = file; this.sourceType = sourceType; } }
| If this is a Java class, returns the .java source file only. | If this is a Stride class, returns the .stride and .java source files, *in that order*. | This is a strict requirement in the call in DataCollectorImpl, do not change the order. | public Collection getAllSourceFilesJavaLast() { List<SourceFileInfo> list = new ArrayList<>(); if (sourceAvailable.equals(SourceType.Stride)) { list.add(new SourceFileInfo(getFrameSourceFile(), SourceType.Stride)); } list.add(new SourceFileInfo(getJavaSourceFile(), SourceType.Java)); return list; }
| @return the name of the context(.ctxt) file this target corresponds to. | public File getContextFile() { return new File(getPackage().getPath(), getBaseName() + ".ctxt"); }
| @return the name of the class (.class) file this target corresponds to. | public File getClassFile() { return new File(getPackage().getPath(), getBaseName() + ".class"); }
| Get the name of the documentation (.html) file corresponding to this target. | public File getDocumentationFile() { String filename = getJavaSourceFile().getPath(); String docFilename = getPackage().getProject().getDocumentationFile(filename); return new File(docFilename); }
| Get a list of .class files for inner classes. | public File [] getInnerClassFiles() { File[] files = getPackage().getPath().listFiles(new InnerClassFileFilter()); return files; }
| A filter to find inner class files. | @OnThread(value = Tag.FXPlatform, ignoreParent = true) class InnerClassFileFilter implements FileFilter {
| Description of the Method | | @param pathname Description of the Parameter | @return Description of the Return Value | @Override public boolean accept(File pathname) { return pathname.getName().startsWith(getBaseName() + "$"); } }
| Get the editor associated with this class. | @return the editor object associated with this target. May be null if | there was a problem opening this editor. | @Override public Editor getEditor() { boolean withInterface; withInterface = this.openWithInterface; return getEditor(withInterface); }
| Gets the editor, if it is already open. If not open, returns | null (without attempting to open it, in contrast to getEditor()) | public Editor getEditorIfOpen() { return editor; }
| Get an editor for this class, either in source view or interface view. | | @param showInterface Determine whether to show interface view or | source view in the editor. | @return the editor object associated with this target. May be null if | there was a problem opening this editor. | private Editor getEditor(boolean showInterface) { if (editor == null) { final String filename; String docFilename = getDocumentationFile().getPath(); if (sourceAvailable == SourceType.NONE) { filename = null; showInterface = true; if (! new File(docFilename).exists()) { return null; } } else { filename = getSourceFile().getPath(); } Project project = getPackage().getProject(); EntityResolver resolver = new PackageResolver(project.getEntityResolver(), getPackage().getQualifiedName()); final FXPlatformRunnable openCallback = () -> { recordEditorOpen(); for (TargetListener stateListener : stateListeners) { stateListener.editorOpened(); } }; if (sourceAvailable == SourceType.Java || sourceAvailable == SourceType.NONE) { editor = EditorManager.getEditorManager().openClass(filename, docFilename, project.getProjectCharset(), getBaseName(), project::getDefaultFXTabbedEditor, this, isCompiled(), resolver, project.getJavadocResolver(), openCallback); } else if (sourceAvailable == SourceType.Stride) { File frameSourceFile = getFrameSourceFile(); File javaSourceFile = getJavaSourceFile(); JavadocResolver javadocResolver = project.getJavadocResolver(); Package pkg = getPackage(); editor = new FrameEditor(frameSourceFile, javaSourceFile, this, resolver, javadocResolver, pkg, openCallback); } if (editor != null) { editor.showInterface(showInterface); } } return editor; }
| Records that the editor for this class target has been opened | (i.e. actually made visible on screen). Further calls after | the first call will be ignored. | private void recordEditorOpen() { if (!hasBeenOpened) { hasBeenOpened = true; switch (sourceAvailable) { case Java: Config.recordEditorOpen(Config.SourceType.Java); break; case Stride: Config.recordEditorOpen(Config.SourceType.Stride); break; default: break; } } }
| Ensure that the source file of this class is up-to-date (i.e. | that any possible unsaved changes in an open editor window are | saved). | | <p>This can cause saveEvent() to be generated, which might move | the class to a new package (if the package line has been changed). | @Override public void ensureSaved() throws IOException { if (editor == null && sourceAvailable == SourceType.Stride) { getEditor(); } super.ensureSaved(); } | Open an inspector window for the class represented by this target. | | @param parent Parent window. | @param animateFromCentre Animate from centre of this node. | private void inspect(Window parent, Node animateFromCentre) { Project proj = getPackage().getProject(); new Thread() { @Override @OnThread(Tag.Worker) public void run() { try { FXPlatformSupplier<DebuggerClass> clss = getPackage().getDebugger().getClass(getQualifiedName(), true); Platform.runLater(() -> proj.getClassInspectorInstance(clss.get(), getPackage(), parent, animateFromCentre)); } catch (ClassNotFoundException cnfe) { } } }.start(); } @Override public void modificationEvent(Editor editor) { invalidate(); removeBreakpoints(); if (getPackage().getProject().getDebugger() != null) { getPackage().getProject().getDebugger().removeBreakpointsForClass(getQualifiedName()); } if (isCompiled()) { setState(State.NEEDS_COMPILE); } sourceInfo.setSourceModified(); } @Override public void saveEvent(Editor editor) { ClassInfo info = analyseSource(); if (info != null) { updateTargetFile(info); } determineRole(null); } @Override public String breakpointToggleEvent(int lineNo, boolean set) { if (isCompiled()) { String possibleError = getPackage().getDebugger().toggleBreakpoint(getQualifiedName(), lineNo, set, null); if (possibleError == null && getPackage() != null) { DataCollector.debuggerBreakpointToggle(getPackage(), getSourceFile(), lineNo, set); } return possibleError; } else { return Config.getString("pkgmgr.breakpointMsg"); } } @Override public void clearAllBreakpoints() { Package pkg = getPackage(); if (pkg != null) pkg.getDebugger().removeBreakpointsForClass(getQualifiedName()); } | Remove all breakpoints in this class. | public void removeBreakpoints() { if (editor != null) { editor.removeBreakpoints(); } }
| Re-initialize the breakpoints which have been set in this | class. | public void reInitBreakpoints() { if (editor != null && isCompiled()) { editor.reInitBreakpoints(); } else if (isCompiled() && sourceAvailable == SourceType.Stride) { List<Integer> breakpoints; breakpoints = new ArrayList<>(this.cachedBreakpoints); for (Integer line : breakpoints) { breakpointToggleEvent(line, true); } } }
| Remove the step mark in this case | (the mark in the editor that shows where execution is) | public void removeStepMark() { if (editor != null) { editor.removeStepMark(); } }
| Gets the compiled attribute of the ClassTarget object | | @return The compiled value | public boolean isCompiled() { return getState() == State.COMPILED; } @Override @OnThread(Tag.FXPlatform) public void scheduleCompilation(boolean immediate, CompileReason reason, CompileType type) { if (Config.isGreenfoot() && type == CompileType.EXPLICIT_USER_COMPILE) { markModified(); getPackage().getProject().scheduleCompilation(immediate, reason, type, getPackage()); } else { getPackage().getProject().scheduleCompilation(immediate, reason, type, this); } }
| Called when this class target has just been successfully compiled. | | We load the compiled class if possible and check if the compilation has | resulted in it taking a different role (ie abstract to applet) | public void analyseAfterCompile() { Class<?> cl = getPackage().loadClass(getQualifiedName()); determineRole(cl); analyseDependencies(cl); analyseTypeParams(cl); }
| Generates a source code skeleton for this class | public boolean generateSkeleton(String template, SourceType sourceType) { if (template == null) { Debug.reportError("generate class skeleton error"); return false; } else { boolean success; switch (sourceType) { case Java: success = role.generateSkeleton(template, getPackage(), getBaseName(), getJavaSourceFile().getPath()); break; case Stride: addStride(Loader.buildTopLevelElement(template, getPackage().getProject().getEntityResolver(), getBaseName(), getPackage().getBaseName())); success = true; break; default: success = false; } if (success) { setState(State.NEEDS_COMPILE); sourceAvailable = sourceType; noSourceLabel.setText(""); return true; } return false; } }
| Inserts a package deceleration in the source file of this class, only if it | is not correct or if it does't exist. Also, the default package will be ignored. | | @param packageName the package's name | @exception IllegalArgumentException if the package name is not a valid java identifier | public void enforcePackage(String packageName) throws IOException { if (getSourceType() != SourceType.Java) { return; } if (!JavaNames.isQualifiedIdentifier(packageName)) { throw new IllegalArgumentException(); } ClassInfo info = sourceInfo.getInfo(getSourceFile(), getPackage()); if (info == null) { return; } String semiReplacement = null; String nameReplacement = null; String pkgStatementReplacement = null; if (packageName.length() == 0) { if (info.hasPackageStatement()) { semiReplacement = ""; nameReplacement = ""; pkgStatementReplacement = ""; } else { return; } } else { if (info.hasPackageStatement()) { if (info.getPackage().equals(packageName)) { return; } nameReplacement = packageName; } else { semiReplacement = ";\n\n"; nameReplacement = packageName; pkgStatementReplacement = "package "; } } FileEditor fed = new FileEditor(getSourceFile()); if (semiReplacement != null) { Selection selSemi = info.getPackageSemiSelection(); fed.replaceSelection(selSemi, semiReplacement); } if (nameReplacement != null) { Selection selName = info.getPackageNameSelection(); fed.replaceSelection(selName, nameReplacement); } if (pkgStatementReplacement != null) { Selection selStatement = info.getPackageStatementSelection(); fed.replaceSelection(selStatement, pkgStatementReplacement); } fed.save(); }
| Analyse the source code, and save retrieved information. | This includes comments and parameter names for methods/constructors, | class name, type parameters, etc. | | Also causes the class role (normal class, unit test, etc) to be | guessed based on the source. | | Note: this should only be called once the containing package is loaded, not | before. All classes must be present in the package or dependency information | will be generated incorrectly during parsing. | public ClassInfo analyseSource() { if (analysing) { return null; } analysing = true; ClassInfo info = sourceInfo.getInfo(getJavaSourceFile(), getPackage()); if (info != null) { determineRole(null); setTypeParameters(info); analyseDependencies(info); } analysing = false; return info; }
| Change file name and package to match that found in the source file. | @param info The information from source analysis | private void updateTargetFile(ClassInfo info) { if (analyseClassName(info)) { if (nameEqualsIgnoreCase(info.getName())) { doClassNameChange(info.getName() + TEMP_FILE_EXTENSION); } doClassNameChange(info.getName()); } if (analysePackageName(info)) { doPackageNameChange(info.getPackage()); } }
| Sets the typeParameters attribute of the ClassTarget object | | @param info The new typeParameters value | private void setTypeParameters(ClassInfo info) { String newTypeParameters = ""; if (info.hasTypeParameter()) { Iterator<String> i = info.getTypeParameterTexts().iterator(); newTypeParameters = "<" + i.next(); while (i.hasNext()){ newTypeParameters += "," + i.next(); } newTypeParameters += ">"; } if (!newTypeParameters.equals(typeParameters)) { typeParameters = newTypeParameters; updateDisplayName(); } }
| Analyses class name of Classtarget with that of parsed src file. Aim is | to detect any textual changes of class name and modify resources to suit | | @param info contains parsed class information | @return true if class name is different | public boolean analyseClassName(ClassInfo info) { String newName = info.getName(); if ((newName == null) || (newName.length() == 0)) { return false; } return (!getBaseName().equals(newName)); }
| Check whether the package name has been changed by comparing the package | name in the information from the parser with the current package name | private boolean analysePackageName(ClassInfo info) { String newName = info.getPackage(); return (!getPackage().getQualifiedName().equals(newName)); }
| Analyse the current dependencies in the source code and update the | dependencies in the graphical display accordingly. | private void analyseDependencies(ClassInfo info) { removeAllOutDependencies(); removeInheritDependencies(); String pkgPrefix = getPackage().getQualifiedName(); pkgPrefix = (pkgPrefix.length() == 0) ? pkgPrefix : pkgPrefix + "."; if (info.getSuperclass() != null) { setSuperClass(info.getSuperclass()); } List<String> vect = info.getImplements(); for (Iterator<String> it = vect.iterator(); it.hasNext();) { String name = it.next(); addInterface(name); } vect = info.getUsed(); for (Iterator<String> it = vect.iterator(); it.hasNext();) { String name = it.next(); DependentTarget used = getPackage().getDependentTarget(name); if (used != null) { UsesDependency dependency = new UsesDependency(getPackage(), this, used); if (used.getAssociation() == this || this.getAssociation() == used) { dependency.setVisible(false); } getPackage().addDependency(dependency); } } }
| Analyse the current dependencies in the compiled class and update the | dependencies in the graphical display accordingly. | public void analyseDependencies(Class<?> cl) { if (cl != null) { removeInheritDependencies(); Class<?> superClass = cl.getSuperclass(); if (superClass != null) { setSuperClass(superClass.getName()); } Class<?> [] interfaces = cl.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { addInterface(interfaces[i].getName()); } } }
| Analyse the type parameters from the compiled class and update the display name. | public <T> void analyseTypeParams(Class<T> cl) { if (cl != null) { String oldTypeParams = typeParameters; TypeVariable<Class<T>> [] tvars = cl.getTypeParameters(); if (tvars.length == 0) { typeParameters = ""; } else { boolean isFirst = true; typeParameters = "<"; for (TypeVariable<?> tvar : tvars) { if (! isFirst) { typeParameters += ","; } isFirst = false; typeParameters += tvar.getName(); } typeParameters += ">"; } if (! typeParameters.equals(oldTypeParams)) { updateDisplayName(); } } }
| Set the superclass. This adds an extends dependency to the appropriate class. | The old extends dependency (if any) must be removed separately. | | @param superName the fully-qualified name of the superclass | private void setSuperClass(String superName) { String pkgPrefix = getPackage().getQualifiedName(); if (superName.startsWith(pkgPrefix)) { int prefixLen = pkgPrefix.length(); prefixLen = prefixLen == 0 ? 0 : prefixLen + 1; superName = superName.substring(prefixLen); DependentTarget superclass = getPackage().getDependentTarget(superName); if (superclass != null) { getPackage().addDependency(new ExtendsDependency(getPackage(), this, superclass)); if (superclass.getState() != State.COMPILED) { markModified(); } } } }
| Add an interface. This adds an implements dependency to the appropriate interface. | private void addInterface(String interfaceName) { String pkgPrefix = getPackage().getQualifiedName(); if (interfaceName.startsWith(pkgPrefix)) { int dotlen = pkgPrefix.length(); dotlen = (dotlen == 0) ? 0 : (dotlen + 1); interfaceName = interfaceName.substring(dotlen); DependentTarget interfce = getPackage().getDependentTarget(interfaceName); if (interfce != null) { getPackage().addDependency(new ImplementsDependency(getPackage(), this, interfce)); if (interfce.getState() != State.COMPILED) { markModified(); } } } }
| Notification that the class represented by this class target has changed name. | private boolean doClassNameChange(String newName) { if (getPackage().getTarget(newName) != null) { getEditor().writeMessage((Config.getString("editor.info.duplication"))); return false; } File oldJavaSourceFile = getJavaSourceFile(); File newJavaSourceFile = new File(getPackage().getPath(), newName + "." + SourceType.Java.toString().toLowerCase()); try { String filename; File oldFrameSourceFile = null; File newFrameSourceFile = null; getPackage().updateTargetIdentifier(this, getIdentifierName(), newName); if (getSourceType().equals(SourceType.Stride)) { newFrameSourceFile = new File(getPackage().getPath(), newName + "." + SourceType.Stride.toString().toLowerCase()); oldFrameSourceFile = getFrameSourceFile(); FileUtility.copyFile(oldFrameSourceFile, newFrameSourceFile); filename = newFrameSourceFile.getAbsolutePath(); } else { filename = newJavaSourceFile.getAbsolutePath(); } FileUtility.copyFile(oldJavaSourceFile, newJavaSourceFile); String javaFilename = newJavaSourceFile.getAbsolutePath(); String docFilename = getPackage().getProject().getDocumentationFile(javaFilename); getEditor().changeName(newName, filename, javaFilename, docFilename); deleteSourceFiles(); getClassFile().delete(); for (File innerClassFile : getInnerClassFiles()) { innerClassFile.delete(); } getContextFile().delete(); getDocumentationFile().delete(); String oldName = getIdentifierName(); setIdentifierName(newName); updateDisplayName(); BClass bClass = getBClass(); ExtensionBridge.ChangeBClassName(bClass, getQualifiedName()); BClassTarget bClassTarget = getBClassTarget(); ExtensionBridge.changeBClassTargetName(bClassTarget, getQualifiedName()); for (Dependency outgoingDependency : dependencies()) { BDependency bDependency = outgoingDependency.getBDependency(); ExtensionBridge.changeBDependencyOriginName(bDependency, getQualifiedName()); } for (Dependency incomingDependency : dependents()) { BDependency bDependency = incomingDependency.getBDependency(); ExtensionBridge.changeBDependencyTargetName(bDependency, getQualifiedName()); } DataCollector.renamedClass(getPackage(), oldFrameSourceFile, newFrameSourceFile, oldJavaSourceFile, newJavaSourceFile); for (TargetListener stateListener : new ArrayList<>(stateListeners)) { stateListener.renamed(newName); } ClassEvent event = new ClassEvent(ClassEvent.CHANGED_NAME, getPackage(), getBClass(), oldName); ExtensionsManager.getInstance().delegateEvent(event); return true; } catch (IOException ioe) { return false; } }
| Update the displayed class name (which includes type parameters). | public void updateDisplayName() { String newDisplayName = getDisplayName(); updateSize(); nameLabel.setText(newDisplayName); setDisplayName(newDisplayName); }
| Delete all the source files (edited and generated) for this target. | private void deleteSourceFiles() { if (getSourceType().equals(SourceType.Stride)) { getJavaSourceFile().delete(); } getSourceFile().delete(); }
| Checks for ClassTarget name equality if case is ignored. | | @param newName | @return true if name is equal ignoring case. | private boolean nameEqualsIgnoreCase(String newName) { return (getBaseName().equalsIgnoreCase(newName)); }
| Change the package of a class target to something else. | | @param newName the new fully qualified package name | private void doPackageNameChange(String newName) { Project proj = getPackage().getProject(); Package dstPkg = proj.getPackage(newName); boolean packageInvalid = dstPkg == null; boolean packageNameClash = dstPkg != null && dstPkg.getTarget(getBaseName()) != null; if (packageInvalid) { DialogManager.showErrorFX(null, "package-name-invalid"); } else { if (packageNameClash) { DialogManager.showErrorFX(null, "package-name-clash"); } else if (DialogManager.askQuestionFX(null, "package-name-changed") == 0) { dstPkg.importFile(getSourceFile()); prepareForRemoval(); getPackage().removeTarget(this); close(); return; } } try { enforcePackage(getPackage().getQualifiedName()); getEditor().reloadFile(); } catch (IOException ioe) { } }
| Resizes the class so the entire classname + type parameter are visible | private void updateSize() { String displayName = getDisplayName(); int width = calculateWidth(nameLabel, displayName); setSize(Math.max(width, (int)pane.getPrefWidth()), getHeight()); repaint(); }
| Post the context menu for this target. | | @param x the x coordinate for the menu, relative to graph editor | @param y the y coordinate for the menu, relative to graph editor | @Override public void popupMenu(int x, int y, PackageEditor graphEditor) { Class<?> cl = null; if (getState() == State.COMPILED) { cl = getPackage().loadClass(getQualifiedName()); if (cl == null) { if (sourceAvailable != SourceType.NONE) { getClassFile().delete(); invalidate(); } } } if (getState() != State.COMPILED) cl = null; Class<?> clFinal = cl; final ClassRole roleFinal; roleFinal = role; SourceType sourceAvailableFinal = sourceAvailable; boolean docExists = getDocumentationFile().exists(); SwingUtilities.invokeLater(() -> { ExtensionsManager extMgr = ExtensionsManager.getInstance(); Platform.runLater(() -> { withMenu(clFinal, roleFinal, sourceAvailableFinal, docExists, menu -> { showingMenu(menu); menu.show(pane, x, y); }, extMgr); }); }); }
| Creates a popup menu for this class target. | | @param extMgr | @param cl class object associated with this class target | @return the created popup menu object | protected void withMenu(Class<?> cl, ClassRole roleRef, SourceType source, boolean docExists, FXPlatformConsumer<ContextMenu> withMenu, ExtensionsManager extMgr) { final ContextMenu menu = new ContextMenu(); roleRef.createRoleMenu(menu.getItems(), this, cl, getState()); if (cl != null) { if (Application.class.isAssignableFrom(cl)) { menu.getItems().add(JavaFXUtil.withStyleClass(JavaFXUtil.makeMenuItem(launchFXStr,() -> { PackageEditor ed = getPackage().getEditor(); Window fxWindow = ed.getFXWindow(); if (getPackage().getProject().getRunOnThread() == null) { int result = DialogManager.askQuestionFX(fxWindow, "run-on-fx"); if (result == 0) getPackage().getProject().setRunOnThread(RunOnThread.FX); else{ getPackage().getProject().setRunOnThread(RunOnThread.DEFAULT); } } CompletableFuture<FXPlatformSupplier<DebuggerResult>> result = getPackage().getDebugger().launchFXApp(cl.getName()); putFXLaunchResult(ed, fxWindow, result); }, null), MENU_STYLE_INBUILT)); } if (roleRef.createClassConstructorMenu(menu.getItems(), this, cl)) { menu.getItems().add(new SeparatorMenuItem()); } if (roleRef.createClassStaticMenu(menu.getItems(), this, cl)) { menu.getItems().add(new SeparatorMenuItem()); } } boolean sourceOrDocExists = source != SourceType.NONE || docExists; menu.getItems().add(new EditAction(sourceOrDocExists)); menu.getItems().add(new CompileAction(source != SourceType.NONE)); menu.getItems().add(new InspectAction(cl != null, null)); menu.getItems().add(new RemoveAction()); menu.getItems().add(new DuplicateClassAction()); Window parentWindow = pane.getScene().getWindow(); if (source == SourceType.Stride) menu.getItems().add(new ConvertToJavaAction(parentWindow)); else if (source == SourceType.Java && roleRef.canConvertToStride()) menu.getItems().add(new ConvertToStrideAction(parentWindow)); roleRef.createRoleMenuEnd(menu.getItems(), this, getState()); FXMenuManager menuManager = new FXMenuManager(menu, extMgr, new ClassExtensionMenu(this)); SwingUtilities.invokeLater(() -> { menuManager.addExtensionMenu(getPackage().getProject()); Platform.runLater(() -> {withMenu.accept(menu); }); }); } private void putFXLaunchResult(PackageEditor ed, Window fxWindow, CompletableFuture<FXPlatformSupplier<DebuggerResult>> result) { result.thenAccept(new Consumer<FXPlatformSupplier<DebuggerResult>>() { @Override @OnThread(Tag.Worker) public void accept(FXPlatformSupplier<DebuggerResult> supplier) { Platform.runLater(() -> { DebuggerResult r = supplier.get(); switch (r.getExitStatus()) { case Debugger.NORMAL_EXIT: DebuggerObject obj = r.getResultObject(); ed.raisePutOnBenchEvent(fxWindow, obj, obj.getGenType(), null, false, Optional.empty()); break; } }); } }); }
| Action which creates a test | @OnThread(Tag.FXPlatform) public class CreateTestAction extends MenuItem {
| Constructor for the CreateTestAction object | public CreateTestAction() { super(createTestStr); setOnAction(e -> actionPerformed(e)); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } @OnThread(Tag.FXPlatform) private void actionPerformed(ActionEvent e) { PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage()); if (pmf != null) { String testClassName = getIdentifierName() + "Test"; pmf.createNewClass(testClassName, "unittest", SourceType.Java, true, -1, -1); Target target = getPackage().getTarget(testClassName); DependentTarget assoc = null; if (target instanceof ClassTarget) { ClassTarget ct = (ClassTarget) target; if (ct != null && ct.isUnitTest()) { assoc = (DependentTarget) getPackage().getTarget(getIdentifierName() + "Test"); } } DependentTarget assocFinal = assoc; PackageEditor pkgEd = getPackage().getEditor(); if (assocFinal != null) setAssociation(assocFinal); updateAssociatePosition(); pkgEd.repaint(); } } }
| Action to open the editor for a classtarget | @OnThread(Tag.FXPlatform) private class EditAction extends MenuItem { public EditAction(boolean enable) { super(editStr); setOnAction(e -> open()); setDisable(!enable); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } }
| Action to compile a classtarget | @OnThread(Tag.FXPlatform) private class CompileAction extends MenuItem { public CompileAction(boolean enable) { super(compileStr); setOnAction(e -> { getPackage().compile(ClassTarget.this, CompileReason.USER, CompileType.EXPLICIT_USER_COMPILE); }); setDisable(!enable); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } }
| Action to remove a classtarget from its package | @OnThread(Tag.FXPlatform) private class RemoveAction extends MenuItem { public RemoveAction() { super(removeStr); setOnAction(e -> actionPerformed(e)); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } @OnThread(Tag.FXPlatform) private void actionPerformed(ActionEvent e) { PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage()); if (pmf.askRemoveClass()) { remove(); } } }
| Action to inspect the static members of a class | @OnThread(Tag.FXPlatform) public class InspectAction extends MenuItem { private final Node animateFromCentreOverride;
| Create an action to inspect a class (i.e. static members, not inspecting an instance) | | @param enable Should the action be enabled? | @param parentOverride If non-null, use this as parent. If null, use PkgMgrFrame window. | @param animateFromCentreOverride If non-null, animate from centre of this node. If null, use ClassTarget's GUI node | public InspectAction(boolean enable, Node animateFromCentreOverride) { super(inspectStr); this.animateFromCentreOverride = animateFromCentreOverride; setOnAction(e -> actionPerformed(e)); setDisable(!enable); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } @OnThread(Tag.FXPlatform) private void actionPerformed(ActionEvent e) { if (checkDebuggerState()) { Window parent = getPackage().getUI().getStage(); Node animateFromCentre = animateFromCentreOverride != null ? animateFromCentreOverride : getNode(); inspect(parent, animateFromCentre); } } } @OnThread(Tag.FXPlatform) public class ConvertToJavaAction extends MenuItem { private final Window parentWindow; public ConvertToJavaAction(Window parentWindow) { super(convertToJavaStr); this.parentWindow = parentWindow; setOnAction(this::actionPerformed); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } private void actionPerformed(ActionEvent e) { if (JavaFXUtil.confirmDialog("convert.to.java.title", "convert.to.java.message", parentWindow, true)) { convertStrideToJava(); } } } @OnThread(Tag.FXPlatform) public class ConvertToStrideAction extends MenuItem { public ConvertToStrideAction(Window parentWindow) { super(convertToStrideStr); setOnAction(e -> promptAndConvertJavaToStride(parentWindow)); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } }
| A menu item to invoke a class duplication. This is valid for | Java and Stride classes. | @OnThread(Tag.FXPlatform) private class DuplicateClassAction extends MenuItem { public DuplicateClassAction() { super(duplicateClassStr); setOnAction(event -> duplicate()); JavaFXUtil.addStyleClass(this, MENU_STYLE_INBUILT); } }
| Converts this Java ClassTarget to Stride, as long as the user | says yes to the dialog that this method shows. | | If warnings (e.g. package-private access converted to protected) | are encountered during the conversion, a dialog is shown to the user | explaining them. Most conversion issues (e.g. unconvertable items) | are warnings not errors. Errors, which stop the process, mainly arise | from unparseable Java source code. | public void promptAndConvertJavaToStride(Window window) { File javaSourceFile = getJavaSourceFile(); Charset projectCharset = getPackage().getProject().getProjectCharset(); if (JavaFXUtil.confirmDialog("convert.to.stride.title", "convert.to.stride.message", window, true)) { try { Parser.ConversionResult javaConvertResult = Parser.javaToStride(Files.readAllLines(javaSourceFile.toPath(), projectCharset).stream().collect(Collectors.joining("\n")), Parser.JavaContext.TOP_LEVEL, false); if (!javaConvertResult.getWarnings().isEmpty()) { new ConvertResultDialog(javaConvertResult.getWarnings().stream().map(ConversionWarning::getMessage).collect(Collectors.toList())).showAndWait(); } List<CodeElement> elements = javaConvertResult.getElements(); if (elements.size() != 1 || !(elements.get(0) instanceof TopLevelCodeElement)) { JavaFXUtil.errorDialog("convert.to.stride.error.title", "convert.to.stride.error.message"); return; } addStride((TopLevelCodeElement)elements.get(0)); DataCollector.convertJavaToStride(getPackage(), javaSourceFile, getFrameSourceFile()); } catch (IOException | ParseFailure pf) { Debug.reportError(pf); new ConvertResultDialog(pf.getMessage()).showAndWait(); } } }
| Process a double click on this target. That is: open its editor. | | @param openInNewWindow if this is true, the editor opens in a new window | @Override public void doubleClick(boolean openInNewWindow) { Editor editor = getEditor(); if (editor == null) { getPackage().showError("error-open-source"); } editor.setEditorVisible(true, openInNewWindow); }
| Set the size of this target. | | @param width The new size value | @param height The new size value | @Override public void setSize(int width, int height) { int w = Math.max(width, MIN_WIDTH); int h = Math.max(height, MIN_HEIGHT); super.setSize(w, h); if (assoc != null) assoc.setSize(w, h); } public void setVisible(boolean vis) { if (vis != this.visible) { this.visible = vis; pane.setVisible(vis); SwingUtilities.invokeLater(() -> { ClassTargetEvent event = new ClassTargetEvent(this, getPackage(), vis); ExtensionsManager.getInstance().delegateEvent(event); }); } } @OnThread(Tag.FXPlatform) @Override protected void redraw() { GraphicsContext g = canvas.getGraphicsContext2D(); double width = canvas.getWidth(); double height = canvas.getHeight(); g.clearRect(0, 0, width, height); if (getState() != State.COMPILED) { g.setFill(hasKnownError() ? getRedStripeFill() : getGreyStripeFill()); g.fillRect(0, 0, width, height); } if (this.selected && isResizable()) { g.setStroke(javafx.scene.paint.Color.BLACK); g.setLineDashes(); g.setLineWidth(1.0); g.strokeLine(width - RESIZE_CORNER_SIZE, height, width, height - RESIZE_CORNER_SIZE); g.strokeLine(width - RESIZE_CORNER_SIZE + RESIZE_CORNER_GAP, height, width, height - RESIZE_CORNER_SIZE + RESIZE_CORNER_GAP); } }
| Gets the grey diagonal stripe pattern used for modified classes. | @OnThread(Tag.FX) public static ImagePattern getGreyStripeFill() { int size = GREY_STRIPE_SEPARATION * 10; if (greyStripeImage == null) { greyStripeImage = JavaFXUtil.createImage(size, size, gImage -> { JavaFXUtil.stripeRect(gImage, 0, 0, size, size, GREY_STRIPE_SEPARATION - STRIPE_THICKNESS, STRIPE_THICKNESS, false, GREY_STRIPE); }); } return new ImagePattern(greyStripeImage, 0, 0, size, size, false); }
| Gets the red diagonal stripe pattern used for classes with an error. | @OnThread(Tag.FX) public static ImagePattern getRedStripeFill() { int size = RED_STRIPE_SEPARATION * 10; if (redStripeImage == null) { redStripeImage = JavaFXUtil.createImage((int)size, (int)size, gImage -> { JavaFXUtil.stripeRect(gImage, 0, 0, size, size, RED_STRIPE_SEPARATION - STRIPE_THICKNESS, STRIPE_THICKNESS, false, RED_STRIPE); JavaFXUtil.stripeRect(gImage, 0, 0, size, size, RED_STRIPE_SEPARATION - STRIPE_THICKNESS, STRIPE_THICKNESS, true, RED_STRIPE); }); } return new ImagePattern(redStripeImage, 0, 0, size, size, false); }
| Prepares this ClassTarget for removal from a Package. It removes | dependency arrows and calls prepareFilesForRemoval() to remove applicable | files. | private void prepareForRemoval() { if (editor != null) { editor.close(); } for (Target o : getPackage().getVertices()) { if (o instanceof DependentTarget) { DependentTarget d = (DependentTarget) o; if (this.equals(d.getAssociation())) { d.setAssociation(null); } } } invalidate(); removeAllInDependencies(); removeAllOutDependencies(); prepareFilesForRemoval(); }
| Removes applicable files (.class, .java and .ctxt) prior to this | ClassTarget being removed from a Package. | public void prepareFilesForRemoval() { List<File> allFiles = getRole().getAllFiles(this); for (Iterator<File> i = allFiles.iterator(); i.hasNext(); ) { i.next().delete(); } } @Override public void generateDoc() { getPackage().generateDocumentation(this); } @Override public void remove() { File frameSourceFile = getSourceType().equals(SourceType.Stride) ? getFrameSourceFile() : null; File javaSourceFile = getJavaSourceFile(); prepareForRemoval(); Package pkg = getPackage(); pkg.removeTarget(this); DataCollector.removeClass(pkg, frameSourceFile, javaSourceFile); if (Config.isGreenfoot()) pkg.rebuild(); }
| Converts this ClassTarget from Stride to Java, by simply | deleting the Stride file and keeping the Java file which we've | always been generating from Stride for compilation purposes. | | This method shows no confirmation dialog/prompt; the caller is expected | to have taken care of that. | | Throws an exception if this is not a Stride ClassTarget. | public void convertStrideToJava() { if (sourceAvailable != SourceType.Stride) throw new IllegalStateException("Cannot convert non-Stride from Stride to Java"); if (editor != null) { editor.close(); try { editor.saveJavaWithoutWarning(); } catch (IOException e) { Debug.reportError(e); } editor = null; } File srcFile = getSourceFile(); if (srcFile.exists()) { srcFile.delete(); } sourceAvailable = SourceType.Java; DataCollector.convertStrideToJava(getPackage(), srcFile, getSourceFile()); }
| Duplicates the class which is represented by this class target | private void duplicate() { String originalClassName = getBaseName(); SourceType sourceType = getSourceType(); PkgMgrFrame pmf = PkgMgrFrame.findFrame(getPackage()); DuplicateClassDialog dialog = new DuplicateClassDialog(pmf.getFXWindow(), "CopyOf" + originalClassName, sourceType); Optional<String> duplicateClassName = dialog.showAndWait(); duplicateClassName.ifPresent(name -> pmf.duplicateClass(originalClassName, name, getSourceFile(), sourceType)); }
| Adds the given stride code element as a Stride file for this | class target, as part of a conversion from Java into Stride, or part | of generating a new class from a template. | | @param element The source code content to put in the new .stride file. | private void addStride(TopLevelCodeElement element) { if (editor != null) { editor.close(); editor = null; } File strideFile = getFrameSourceFile(); try { Files.write(strideFile.toPath(), Arrays.asList(Utility.splitLines(Utility.serialiseCodeToString(element.toXML()))), Charset.forName("UTF-8")); } catch (IOException e) { Debug.reportError(e); JavaFXUtil.errorDialog(Config.getString("convert.to.stride.title"), e.getMessage()); return; } sourceAvailable = SourceType.Stride; } public boolean isMoveable() { return isMoveable; }
| Set whether this ClassTarget can be moved by the user (dragged around). | This is set false for unit tests which are associated with another class. | | @see bluej.graph.Moveable#setIsMoveable(boolean) | public void setIsMoveable(boolean isMoveable) { this.isMoveable = isMoveable; }
| Perform interactive method call | @Override public void executeMethod(MethodView mv) { getPackage().callStaticMethodOrConstructor(mv); }
| Interactive constructor call | @Override public void callConstructor(ConstructorView cv) { getPackage().callStaticMethodOrConstructor(cv); }
| Method to check state of debug VM (currently running may cause problems) | and then give options accordingly. | Returns a value from user about how to continue i.e should the original requested be executed. | | @return Whether the original request should be executed (dependent on how the user wants to proceed) | private boolean checkDebuggerState() { return ProjectUtils.checkDebuggerState(getPackage().getProject(), getPackage().getUI().getStage()); }
| Returns the naviview expanded value from the properties file | @return | public boolean isNaviviewExpanded() { return isNaviviewExpanded.orElse(false); }
| Sets the naviview expanded value from the properties file to this local variable | @param isNaviviewExpanded | public void setNaviviewExpanded(boolean isNaviviewExpanded) { this.isNaviviewExpanded = Optional.of(isNaviviewExpanded); }
| Retrieves a property from the editor | @Override public String getProperty(String key) { return properties.get(key); }
| Sets a property for the editor | @Override public void setProperty(String key, String value) { properties.put(key, value); } @Override public void recordJavaEdit(String latest, boolean includeOneLineEdits) { DataCollector.editJava(getPackage(), getJavaSourceFile(), latest, includeOneLineEdits); } @Override public void recordStrideEdit(String latestJava, String latestStride, StrideEditReason reason) { DataCollector.editStride(getPackage(), getJavaSourceFile(), latestJava, getFrameSourceFile(), latestStride, reason); } @Override public void recordClose() { if (hasSourceCode()) { DataCollector.closeClass(getPackage(), getSourceFile()); } recordedAsOpen = false; } @Override public void recordOpen() { if (recordedAsOpen == false && hasSourceCode()) { DataCollector.openClass(getPackage(), getSourceFile()); recordedAsOpen = true; } } @Override public void recordSelected() { if (hasSourceCode()) { DataCollector.selectClass(getPackage(), getSourceFile()); } } public CompileInputFile getCompileInputFile() { return new CompileInputFile(getJavaSourceFile(), getSourceFile()); }
| Display a compilation diagnostic (error message), if possible and appropriate. The editor | decides if it is appropriate to display the error and may have a policy where eg it only | shows a limited number of errors. | | @param diagnostic the compiler-generated diagnostic | @param errorIndex the index of the error in this batch (first error is 0) | @param compileType the type of compilation leading to the error | @return true if the diagnostic was displayed to the user | public boolean showDiagnostic(Diagnostic diagnostic, int errorIndex, CompileType compileType) { if (compilationInvalid) { return false; } Editor ed = getEditor(); if (ed == null) { return false; } setState(State.HAS_ERROR); return ed.displayDiagnostic(diagnostic, errorIndex, compileType); }
| Check whether there was a compilation error for this target, last time | compilation was attempted. | @OnThread(Tag.Any) public boolean hasKnownError() { return getState() == State.HAS_ERROR; } @Override public void recordShowErrorMessage(int identifier, List<String> quickFixes) { DataCollector.showErrorMessage(getPackage(), identifier, quickFixes); } @Override public void recordShowErrorIndicators(Collection<Integer> identifiers) { DataCollector.showErrorIndicators(getPackage(), identifiers); } @Override public void recordEarlyErrors(List<DiagnosticWithShown> diagnostics, int compilationIdentifier) { if (diagnostics.isEmpty()) return; DataCollector.compiled(getPackage().getProject(), getPackage(), new CompileInputFile[] {getCompileInputFile() }, diagnostics, false, CompileReason.EARLY, compilationIdentifier); } @Override public void recordLateErrors(List<DiagnosticWithShown> diagnostics, int compilationIdentifier) { if (diagnostics.isEmpty()) return; DataCollector.compiled(getPackage().getProject(), getPackage(), new CompileInputFile[] {getCompileInputFile() }, diagnostics, false, CompileReason.LATE, compilationIdentifier); } @Override public void recordFix(int errorIdentifier, int fixIndex) { DataCollector.fixExecuted(getPackage(), errorIdentifier, fixIndex); } @Override public void recordCodeCompletionStarted(Integer lineNumber, Integer columnNumber, String xpath, Integer subIndex, String stem, int codeCompletionId) { DataCollector.codeCompletionStarted(this, lineNumber, columnNumber, xpath, subIndex, stem, codeCompletionId); } @Override public void recordCodeCompletionEnded(Integer lineNumber, Integer columnNumber, String xpath, Integer elementOffset, String stem, String replacement, int codeCompletionId) { DataCollector.codeCompletionEnded(this, lineNumber, columnNumber, xpath, elementOffset, stem, replacement, codeCompletionId); } @Override public void recordUnknownCommandKey(String enclosingFrameXpath, int cursorIndex, char key) { DataCollector.unknownFrameCommandKey(this, enclosingFrameXpath, cursorIndex, key); } @Override public void recordShowHideFrameCatalogue(String enclosingFrameXpath, int cursorIndex, boolean show, FrameCatalogue.ShowReason reason) { DataCollector.showHideFrameCatalogue(getPackage().getProject(), getPackage(), enclosingFrameXpath, cursorIndex, show, reason); } @Override public void recordViewModeChange(String enclosingFrameXpath, int cursorIndex, Frame.View oldView, Frame.View newView, Frame.ViewChangeReason reason) { DataCollector.viewModeChange(getPackage(), getSourceFile(), enclosingFrameXpath, cursorIndex, oldView, newView, reason); } @Override public boolean isFront() { return isFront; } @Override public void showingInterface(boolean showing) { this.showingInterface = showing; } @Override public void setCreatingExtends(boolean drawingExtends) { this.drawingExtends = drawingExtends; } @Override public boolean cursorAtResizeCorner(MouseEvent e) { return super.cursorAtResizeCorner(e) && !drawingExtends; } }
top, use, map, class ClassTarget

.   ClassTarget
.   ClassTarget
.   ClassRole>>asList
.   resize
.   calcSourceAvailable
.   getBClass
.   getBClassTarget
.   getQualifiedName
.   getBaseName
.   getSourceInfo
.   getTypeReflective
.   getDisplayName
.   getTypeParameters
.   setState
.   markCompiling
.   getRole
.   setRole
.   pseudoFor
.   isJunit4TestClass
.   Class.forName
.   Class.forName
.   Class.forName
.   determineRole
.   load
.   save
.   reload
.   upToDate
.   fixSourceModificationDate
.   invalidate
.   isInterface
.   isUnitTest
.   isEnum
.   isAbstract
.   hasSourceCode
.   getSourceType
.   getJavaSourceFile
.   getFrameSourceFile
.   getSourceFile
.   isVisible
.   markCompiled

top, use, map, class SourceFileInfo

.   SourceFileInfo
.   getAllSourceFilesJavaLast
.   getContextFile
.   getClassFile
.   getDocumentationFile
.   getInnerClassFiles

top, use, map, class InnerClassFileFilter

.   accept
.   getEditor
.   getEditorIfOpen
.   getEditor
.   recordEditorOpen
.   ensureSaved
.   inspect
.   run
.   modificationEvent
.   saveEvent
.   breakpointToggleEvent
.   clearAllBreakpoints
.   removeBreakpoints
.   reInitBreakpoints
.   removeStepMark
.   isCompiled
.   scheduleCompilation
.   analyseAfterCompile
.   generateSkeleton
.   enforcePackage
.   analyseSource
.   updateTargetFile
.   setTypeParameters
.   analyseClassName
.   analysePackageName
.   analyseDependencies
.   analyseDependencies
.   analyseTypeParams
.   setSuperClass
.   addInterface
.   doClassNameChange
.   updateDisplayName
.   deleteSourceFiles
.   nameEqualsIgnoreCase
.   doPackageNameChange
.   updateSize
.   popupMenu
.   withMenu
.   putFXLaunchResult
.   accept

top, use, map, class CreateTestAction

.   CreateTestAction
.   actionPerformed

top, use, map, class EditAction

.   EditAction

top, use, map, class CompileAction

.   CompileAction

top, use, map, class RemoveAction

.   RemoveAction
.   actionPerformed

top, use, map, class InspectAction

.   InspectAction
.   actionPerformed

top, use, map, class ConvertToJavaAction

.   ConvertToJavaAction
.   actionPerformed

top, use, map, class ConvertToStrideAction

.   ConvertToStrideAction

top, use, map, class DuplicateClassAction

.   DuplicateClassAction
.   promptAndConvertJavaToStride
.   doubleClick
.   setSize
.   setVisible
.   redraw
.   getGreyStripeFill
.   getRedStripeFill
.   prepareForRemoval
.   prepareFilesForRemoval
.   generateDoc
.   remove
.   convertStrideToJava
.   duplicate
.   addStride
.   isMoveable
.   setIsMoveable
.   executeMethod
.   callConstructor
.   checkDebuggerState
.   isNaviviewExpanded
.   setNaviviewExpanded
.   getProperty
.   setProperty
.   recordJavaEdit
.   recordStrideEdit
.   recordClose
.   recordOpen
.   recordSelected
.   getCompileInputFile
.   showDiagnostic
.   hasKnownError
.   recordShowErrorMessage
.   recordShowErrorIndicators
.   recordEarlyErrors
.   recordLateErrors
.   recordFix
.   recordCodeCompletionStarted
.   recordCodeCompletionEnded
.   recordUnknownCommandKey
.   recordShowHideFrameCatalogue
.   recordViewModeChange
.   isFront
.   showingInterface
.   setCreatingExtends
.   cursorAtResizeCorner




3170 neLoCode + 249 LoComm