package bluej.pkgmgr;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import bluej.debugger.DebuggerObject;
import bluej.extensions.event.DependencyEvent;
import bluej.views.CallableView;
import javafx.application.Platform;
import bluej.compiler.CompileInputFile;
import bluej.compiler.CompileReason;
import bluej.compiler.CompileType;
import bluej.editor.stride.FrameEditor;
import bluej.pkgmgr.target.CSSTarget;
import bluej.pkgmgr.target.DependentTarget.State;
import bluej.pkgmgr.dependency.ExtendsDependency;
import bluej.pkgmgr.dependency.ImplementsDependency;
import bluej.utility.javafx.JavaFXUtil;
import bluej.Config;
import bluej.collect.DataCollectionCompileObserverWrapper;
import bluej.collect.DataCollector;
import bluej.compiler.CompileObserver;
import bluej.compiler.Diagnostic;
import bluej.compiler.FXCompileObserver;
import bluej.compiler.EventqueueCompileObserverAdapter;
import bluej.compiler.JobQueue;
import bluej.debugger.Debugger;
import bluej.debugger.DebuggerEvent;
import bluej.debugger.DebuggerListener;
import bluej.debugger.DebuggerThread;
import bluej.debugger.ExceptionDescription;
import bluej.debugger.SourceLocation;
import bluej.debugmgr.CallHistory;
import bluej.debugmgr.Invoker;
import bluej.editor.Editor;
import bluej.editor.TextEditor;
import bluej.extensions.BPackage;
import bluej.extensions.ExtensionBridge;
import bluej.extensions.SourceType;
import bluej.extensions.event.CompileEvent;
import bluej.extmgr.ExtensionsManager;
import bluej.parser.AssistContent;
import bluej.parser.AssistContent.CompletionKind;
import bluej.parser.ExpressionTypeInfo;
import bluej.parser.ParseUtils;
import bluej.parser.nodes.ParsedCUNode;
import bluej.parser.symtab.ClassInfo;
import bluej.pkgmgr.dependency.Dependency;
import bluej.pkgmgr.dependency.UsesDependency;
import bluej.pkgmgr.target.ClassTarget;
import bluej.pkgmgr.target.DependentTarget;
import bluej.pkgmgr.target.EditableTarget;
import bluej.pkgmgr.target.PackageTarget;
import bluej.pkgmgr.target.ParentPackageTarget;
import bluej.pkgmgr.target.ReadmeTarget;
import bluej.pkgmgr.target.Target;
import bluej.pkgmgr.target.TargetCollection;
import bluej.prefmgr.PrefMgr;
import bluej.utility.Debug;
import bluej.utility.DialogManager;
import bluej.utility.FileUtility;
import bluej.utility.JavaNames;
import bluej.utility.SortedProperties;
import bluej.utility.Utility;
import bluej.utility.filefilter.FrameSourceFilter;
import bluej.utility.filefilter.JavaClassFilter;
import bluej.utility.filefilter.JavaSourceFilter;
import bluej.utility.filefilter.SubPackageFilter;
import threadchecker.OnThread;
import threadchecker.Tag;
| A Java package (collection of Java classes).
|
| @author Michael Kolling
| @author Axel Schmolitzky
| @author Andrew Patterson
|
public final class Package
{
| message to be shown on the status bar
|
static final String compiling = Config.getString("pkgmgr.compiling");
| message to be shown on the status bar
|
static final String compileDone = Config.getString("pkgmgr.compileDone");
| message to be shown on the status bar
|
static final String chooseUsesTo = Config.getString("pkgmgr.chooseUsesTo");
| message to be shown on the status bar
|
static final String chooseInhTo = Config.getString("pkgmgr.chooseInhTo");
| The name of the package file in a package directory that holds
| information about the package and its targets.
|
@OnThread(value = Tag.Any, requireSynchronized = true)
private PackageFile packageFile;
| Readme file name
|
public static final String readmeName = "README.TXT";
| error code
|
public static final int NO_ERROR = 0;
| error code
|
public static final int FILE_NOT_FOUND = 1;
| error code
|
public static final int ILLEGAL_FORMAT = 2;
| error code
|
public static final int COPY_ERROR = 3;
| error code
|
public static final int CLASS_EXISTS = 4;
| error code
|
public static final int CREATE_ERROR = 5;
@OnThread(value = Tag.Any, requireSynchronized = true)
private final List<Target> targetsToPlace = new ArrayList<>();
private boolean recorded = false;
| Reason code for displaying source line
|
private enum ShowSourceReason
{
STEP_OR_HALT,
BREAKPOINT_HIT,
FRAME_SELECTED;
| Check whether this reason corresponds to a suspension event (breakpoint/step/etc).
|
public boolean isSuspension()
{
return this == STEP_OR_HALT || this == BREAKPOINT_HIT;
}
}
| In the top left corner of each package we have a fixed target - either a
| ParentPackageTarget or a ReadmeTarget. These are there locations
|
public static final int FIXED_TARGET_X = 10;
public static final int FIXED_TARGET_Y = 10;
| the Project this package is in
|
private final Project project;
| The parent Package object for this package or null if this is the unnamed
| package ie. the root of the package tree
|
private final Package parentPackage;
| base name of package (eg util) ("" for the unnamed package) */
|private final String baseName;
/**
* this properties object contains the properties loaded off disk for this
* package, or the properties which were most recently saved to disk for
| this package
|
private volatile SortedProperties lastSavedProps = new SortedProperties();
| all the targets in a package
|
@OnThread(value = Tag.Any, requireSynchronized = true)
private final TargetCollection targets;
| Holds the choice of "from" target for a new dependency */
|@OnThread(Tag.FXPlatform)
private DependentTarget fromChoice;
/** the CallHistory of a package */
private CallHistory callHistory;
/**
| needed when debugging with breakpoints to see if the editor window needs
| to be brought to the front
|
private String lastSourceName = "";
| determines the maximum length of the CallHistory of a package
|
public static final int HISTORY_LENGTH = 6;
@OnThread(value = Tag.Any, requireSynchronized = true)
private PackageListener editor;
private PackageUI ui;
@OnThread(Tag.FXPlatform)
private List<PackageListener> listeners = new ArrayList<>();
List<UsesDependency> getUsesArrows()
{
return usesArrows;
}
List<Dependency> getExtendsArrows()
{
return extendsArrows;
}
@OnThread(value = Tag.FXPlatform)
private final List<UsesDependency> usesArrows = new ArrayList<>();
@OnThread(value = Tag.FXPlatform)
private final List<Dependency> extendsArrows = new ArrayList<>();
| True if we currently have a compile queued up waiting for debugger to become idle
|
@OnThread(Tag.FXPlatform)
private boolean waitingForIdleToCompile = false;
| Whether we have issued a package compilation, and not yet seen its conclusion
|
private boolean currentlyCompiling = false;
| Whether a compilation has been queued (behind the current compile job). Only one compile can be queued.
|
private boolean queuedCompile = false;
private CompileReason queuedReason;
private final List<FXCompileObserver> compileObservers = new ArrayList<>();
| File pointing at the directory for this package
|
@OnThread(Tag.Any)
private File dir;
| Create a package of a project with the package name of baseName (ie
| reflect) and with a parent package of parent (which may represent
| java.lang for instance) If the package file (bluej.pkg) is not found, an
| IOException is thrown.
|
public Package(Project project, String baseName, Package parent)
throws IOException
{
if (parent == null)
throw new NullPointerException("Package must have a valid parent package");
if (baseName.length() == 0)
throw new IllegalArgumentException("unnamedPackage must be created using Package(project)");
if (!JavaNames.isIdentifier(baseName))
throw new IllegalArgumentException(baseName + " is not a valid name for a Package");
this.project = project;
this.baseName = baseName;
this.parentPackage = parent;
this.targets = new TargetCollection();
init();
}
| Create the unnamed package of a project If the package file (bluej.pkg)
| is not found, an IOException is thrown.
|
public Package(Project project)
throws IOException
{
this.project = project;
this.baseName = "";
this.parentPackage = null;
this.targets = new TargetCollection();
init();
}
private void init()
throws IOException
{
callHistory = new CallHistory(HISTORY_LENGTH);
dir = new File(project.getProjectDir(), getRelativePath().getPath());
load();
}
@OnThread(Tag.Any)
public boolean isUnnamedPackage()
{
return parentPackage == null;
}
| Return the project this package belongs to.
|
@OnThread(Tag.Any)
public Project getProject()
{
return project;
}
@OnThread(value = Tag.Any,requireSynchronized = true)
private BPackage singleBPackage;
| Return the extensions BPackage associated with this Package.
| There should be only one BPackage object associated with each Package.
| @return the BPackage associated with this Package.
|
@OnThread(Tag.Any)
public synchronized final BPackage getBPackage()
{
if ( singleBPackage == null )
singleBPackage = ExtensionBridge.newBPackage(this);
return singleBPackage;
}
| Get the unique identifier for this package (it's directory name at
| present)
|
@OnThread(Tag.Any)
public String getId()
{
return getPath().getPath();
}
| Return this package's base name (eg util) ("" for the unnamed package)
|*/
@OnThread(Tag.Any)
public String getBaseName()
{
return baseName;
}
/**
* Return the qualified name of an identifier in this package (eg
| java.util.Random if given Random)
|
@OnThread(Tag.Any)
public String getQualifiedName(String identifier)
{
if (isUnnamedPackage())
return identifier;
else{ return getQualifiedName() + "." + identifier;
}
}
| Return the qualified name of the package (eg. java.util) ("" for the
|* unnamed package)
*/
@OnThread(Tag.Any)
public String getQualifiedName()
{
Package currentPkg = this;
String retName = "";
while (!currentPkg.isUnnamedPackage()){
if (retName.equals("")) {
retName = currentPkg.getBaseName();
}
else {
retName = currentPkg.getBaseName() + "." + retName;
}
currentPkg = currentPkg.getParent();
}
return retName;
}
/**
* get the readme target for this package
*
*/
public synchronized ReadmeTarget getReadmeTarget()
|
|{
|
|ReadmeTarget readme = (ReadmeTarget) targets.get(ReadmeTarget.README_ID);
|
|return readme;
|
|}
|
|/**
| Construct a path for this package relative to the project.
|
| @return The relative path.
|
private File getRelativePath()
{
Package currentPkg = this;
File retFile = new File(currentPkg.getBaseName());
|
| loop through our parent packages constructing a relative path for
| this file
|
while (!currentPkg.isUnnamedPackage()){
currentPkg = currentPkg.getParent();
retFile = new File(currentPkg.getBaseName(), retFile.getPath());
}
return retFile;
}
| Return a file object of the directory location of this package.
|
| @return The file object representing the full path to the packages
| directory
|
@OnThread(Tag.Any)
public File getPath()
{
return dir;
}
| Return our parent package or null if we are the unnamed package.
|
@OnThread(Tag.Any)
public Package getParent()
{
return parentPackage;
}
| Returns the sub-package if this package is "boring". Our definition of
|* boring is that the package has no classes in it and only one sub package.
* If this package is not boring, this method returns null.
*/
protected synchronized Package getBoringSubPackage()
|
|{
|
|PackageTarget pt = null;
|
|for (Iterator<Target> e = targets.iterator(); e.hasNext();) {
|
|Target target = e.next();
|
|if (target instanceof ClassTarget)
|
|return null;
|
|if ((target instanceof PackageTarget) && !(target instanceof ParentPackageTarget)) {
|
|// we have found our second sub package
|
|// this means this package is not boring
|
|if (pt != null)
|
|return null;
|
|pt = (PackageTarget) target;
|
|}
|
|}
|
|if (pt == null)
|
|return null;
|
|return getProject().getPackage(pt.getQualifiedName());
|
|}
|
|/**
| Return an array of package objects which are nested one level below us.
|
| @param getUncached should be true if unopened packages should be included
|
protected synchronized List getChildren(boolean getUncached)
{
List<Package> children = new ArrayList<Package>();
for (Iterator<Target> e = targets.iterator(); e.hasNext();) {
Target target = e.next();
if (target instanceof PackageTarget && !(target instanceof ParentPackageTarget)) {
PackageTarget pt = (PackageTarget) target;
Package child;
if (getUncached) {
child = getProject().getPackage(pt.getQualifiedName());
}
else {
child = getProject().getCachedPackage(pt.getQualifiedName());
}
if (child == null)
continue;
children.add(child);
}
}
return children;
}
public void setStatus(String msg)
{
PkgMgrFrame.displayMessage(this, msg);
}
| Sets the PackageEditor for this package.
| @param ed The PackageEditor. Non-null when opening, null when
| closing.
|
@OnThread(Tag.FXPlatform)
p.public void setEditor(PackageEditor ed)
{
setUI(ed);
synchronized (this)
{
if (this.editor != null)
{
removeListener(ed);
}
this.editor = ed;
if (ed != null)
{
addListener(ed);
}
}
if (ed == null) {
fireClosedEvent();
}
if (ed != null)
{
synchronized (this)
{
for (Target t : targets)
{
if (t instanceof ParentPackageTarget)
{
ed.findSpaceForVertex(t);
}
}
for (Target t : targetsToPlace)
{
ed.findSpaceForVertex(t);
}
targetsToPlace.clear();
}
ed.graphChanged();
}
}
| Get the editor for this package, as a PackageEditor. This should be considered deprecated;
| use getUI() instead if possible. May return null.
|
@OnThread(Tag.Any)
public synchronized PackageEditor getEditor()
{
return (PackageEditor) editor;
}
| Set the UI controller for this package.
|
public void setUI(PackageUI ui)
{
this.ui = ui;
}
| Retrieve the UI controller for this package. (May return null if no UI has been set; however,
| most operations requiring the UI should be performed in contexts where the UI has been set, so
| it should normally be safe to assume non-null return).
|
public PackageUI getUI()
{
return ui;
}
| Add a listener for this package.
|
public synchronized void addListener(PackageListener pl)
{
listeners.add(pl);
}
| Remove a listener for this package.
|
public synchronized void removeListener(PackageListener pl)
{
listeners.remove(pl);
}
| Fire a "package closed" event to listeners.
|*/
@OnThread(Tag.FXPlatform)
private void fireClosedEvent()
{
// Note we take a copy of the listener list as listeners will probably be removed during processing.
|
|List<PackageListener> listenersCopy = new ArrayList<PackageListener>(listeners);
|
|for (PackageListener l : listenersCopy)
|
|{
|
|l.graphClosed();
|
|}
|
|}
|
|/**
| Fire a "graph changed" event to listeners.
|*/
@OnThread(Tag.FXPlatform)
private void fireChangedEvent()
{
for (PackageListener l : listeners)
{
l.graphChanged();
}
}
|
|/**
| Get the package properties, as most recently saved. The returned Properties set should be considered
| immutable.
|
@OnThread(Tag.Any)
public Properties getLastSavedProperties()
{
return lastSavedProps;
}
| Get the currently selected Targets. It will return an empty array if no
| target is selected.
|
| @return the currently selected array of Targets.
|
@OnThread(Tag.Any)
public synchronized List getSelectedTargets()
{
return Utility.filterList(getVertices(), Target::isSelected);
}
| Search a directory for Java source and class files and add their names to
| a set which is returned. Will delete any __SHELL files which are found in
| the directory and will ignore any single .class files which do not
| contain public classes.
|
| The returned set is guaranteed to be only valid Java identifiers.
|
private Set findTargets(File path)
{
File javaSrcFiles[] = path.listFiles(new JavaSourceFilter());
File frameSrcFiles[] = path.listFiles(new FrameSourceFilter());
File classFiles[] = path.listFiles(new JavaClassFilter());
Set<String> interestingSet = new HashSet<String>();
for (int i = 0; i < javaSrcFiles.length; i++) {
if (javaSrcFiles[i].getName().startsWith(Invoker.SHELLNAME)) {
javaSrcFiles[i].delete();
continue;
}
String javaFileName = JavaNames.stripSuffix(javaSrcFiles[i].getName(), "." + SourceType.Java.toString().toLowerCase());
if (!JavaNames.isIdentifier(javaFileName))
continue;
if (javaFileName.indexOf('$') == -1)
interestingSet.add(javaFileName);
}
for (int i = 0; i < frameSrcFiles.length; i++) {
String frameFileName = JavaNames.stripSuffix(frameSrcFiles[i].getName(), "." + SourceType.Stride.toString().toLowerCase());
if (!JavaNames.isIdentifier(frameFileName))
continue;
interestingSet.add(frameFileName);
}
for (int i = 0; i < classFiles.length; i++) {
if (classFiles[i].getName().startsWith(Invoker.SHELLNAME)) {
classFiles[i].delete();
continue;
}
String classFileName = JavaNames.stripSuffix(classFiles[i].getName(), ".class");
if (!JavaNames.isIdentifier(classFileName))
continue;
if (classFileName.indexOf('$') == -1) {
if (!interestingSet.contains(classFileName)) {
try {
Class<?> c = loadClass(getQualifiedName(classFileName));
if (c != null && Modifier.isPublic(c.getModifiers()))
interestingSet.add(classFileName);
}
catch (LinkageError e) {
Debug.message(e.toString());
}
}
}
}
return interestingSet;
}
| Load the elements of a package from a specified directory. If the package
| file (bluej.pkg) is not found, an IOException is thrown.
|
| <p>This does not cause targets to be loaded. Use refreshPackage() for that.
|
public synchronized void load()
throws IOException
{
packageFile = getPkgFile();
packageFile.load(lastSavedProps);
}
| Refresh the targets and dependency arrows in the package, based on whatever
| is actually on disk.
|
public void refreshPackage()
{
Map<String,Target> propTargets = new HashMap<String,Target>();
int numTargets = 0, numDependencies = 0;
try {
numTargets = Integer.parseInt(lastSavedProps.getProperty("package.numTargets", "0"));
numDependencies = Integer.parseInt(lastSavedProps.getProperty("package.numDependencies", "0"));
}
catch (Exception e) {
synchronized (this)
{
Debug.reportError("Error loading from package file " + packageFile + ": " + e, e);
}
return;
}
for (int i = 0; i < numTargets; i++) {
Target target;
String type = lastSavedProps.getProperty("target" + (i + 1) + ".type");
String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
if ("PackageTarget".equals(type))
{
target = new PackageTarget(this, identifierName);
}
else if ("CSSTarget".equals(type))
{
target = new CSSTarget(this, new File(getPath(), identifierName));
}
else
{
target = new ClassTarget(this, identifierName);
}
target.load(lastSavedProps, "target" + (i + 1));
propTargets.put(identifierName, target);
}
addImmovableTargets();
File subDirs[] = getPath().listFiles(new SubPackageFilter());
for (int i = 0; i < subDirs.length; i++) {
if (!JavaNames.isIdentifier(subDirs[i].getName()))
continue;
Target target = propTargets.get(subDirs[i].getName());
if (target == null || !(target instanceof PackageTarget)) {
target = new PackageTarget(this, subDirs[i].getName());
synchronized (this)
{
targetsToPlace.add(target);
}
}
addTarget(target);
}
if (!Config.isGreenfoot())
{
File cssFiles[] = getPath().listFiles(p -> p.getName().endsWith(".css"));
for (File cssFile : cssFiles)
{
Target target = propTargets.get(cssFile.getName());
if (target == null || !(target instanceof CSSTarget))
{
target = new CSSTarget(this, cssFile);
synchronized (this)
{
targetsToPlace.add(target);
}
}
addTarget(target);
}
}
Set<String> interestingSet = findTargets(getPath());
Iterator<String> it = interestingSet.iterator();
while (it.hasNext()){
String targetName = it.next();
Target target = propTargets.get(targetName);
if (target == null || !(target instanceof ClassTarget)) {
target = new ClassTarget(this, targetName);
synchronized (this)
{
targetsToPlace.add(target);
}
}
addTarget(target);
}
if (!recorded)
{
DataCollector.packageOpened(this);
recorded = true;
}
List<Target> targetsCopy;
synchronized (this)
{
targetsCopy = targets.toList();
}
for (Target target : targetsCopy) {
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
ct.setState(State.COMPILED);
}
}
for (int i = 0; i < numDependencies; i++) {
String type = lastSavedProps.getProperty("dependency" + (i + 1) + ".type");
if ("UsesDependency".equals(type)) {
try
{
UsesDependency newDep = new UsesDependency(this, lastSavedProps, "dependency" + (i + 1));
addDependency(newDep, false);
}
catch (Dependency.DependencyNotFoundException e)
{
Debug.reportError(e);
}
}
}
recalcArrows();
LinkedList<ClassTarget> invalidated = new LinkedList<ClassTarget>();
for (Target target : targetsCopy) {
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
if (ct.isCompiled() && !ct.upToDate()) {
ct.setState(State.NEEDS_COMPILE);
invalidated.add(ct);
}
}
}
while (! invalidated.isEmpty()){
ClassTarget ct = invalidated.removeFirst();
for (Dependency dependent : ct.dependentsAsList()) {
DependentTarget dt = dependent.getFrom();
if (dt instanceof ClassTarget) {
ClassTarget dep = (ClassTarget) dt;
if (dep.isCompiled() && dep.hasSourceCode()) {
dep.setState(State.NEEDS_COMPILE);
invalidated.add(dep);
}
}
}
}
for (Target target : targetsCopy) {
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
if (ct.isCompiled()) {
Class<?> cl = loadClass(ct.getQualifiedName());
ct.determineRole(cl);
ct.analyseDependencies(cl);
ct.analyseTypeParams(cl);
if (cl == null) {
ct.setState(State.NEEDS_COMPILE);
}
}
else {
ct.analyseSource();
try {
if ( !ct.getSourceType().equals(SourceType.Stride))
ct.enforcePackage(getQualifiedName());
}
catch (IOException ioe) {
Debug.message("Error enforcing class package: " + ioe.getLocalizedMessage());
}
}
}
}
for (int i = 0; i < numTargets; i++) {
String assoc = lastSavedProps.getProperty("target" + (i + 1) + ".association");
String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
if (assoc != null) {
Target t1 = getTarget(identifierName), t2 = getTarget(assoc);
if (t1 != null && t2 != null && t1 instanceof DependentTarget) {
DependentTarget dt = (DependentTarget) t1;
dt.setAssociation((DependentTarget)t2);
}
}
}
}
| Returns the file containing information about the package.
| For BlueJ this is package.bluej (or for older versions bluej.pkg)
| and for Greenfoot it is greenfoot.project.
|
private PackageFile getPkgFile()
{
File dir = getPath();
return PackageFileFactory.getPackageFile(dir);
}
| Position a target which has been added, based on the layout file
| (if an entry exists) or find a suitable position otherwise.
|
| @param t the target to position
|
public void positionNewTarget(Target t)
{
String targetName = t.getIdentifierName();
try {
int numTargets = Integer.parseInt(lastSavedProps.getProperty("package.numTargets", "0"));
for (int i = 0; i < numTargets; i++) {
String identifierName = lastSavedProps.getProperty("target" + (i + 1) + ".name");
if (identifierName.equals(targetName)) {
t.load(lastSavedProps, "target" + (i + 1));
return;
}
}
}
catch (NumberFormatException e) {
}
getEditor().findSpaceForVertex(t);
}
| Add our immovable targets (the readme file, and possibly a link to the
| parent package)
|
private void addImmovableTargets()
{
Target t = new ReadmeTarget(this);
t.load(lastSavedProps, "readme");
t.setPos(FIXED_TARGET_X, FIXED_TARGET_Y);
addTarget(t);
if (!isUnnamedPackage()) {
final Target parent = new ParentPackageTarget(this);
PackageEditor ed = getEditor();
if (ed != null)
ed.findSpaceForVertex(parent);
addTarget(parent);
}
}
| Reload a package.
|
| This means we check the existing directory contents and compare it
| against the targets we have in the package. Any new directories or java
| source is added to the package. This function will not remove targets
| that have had their corresponding on disk counterparts removed.
|
| Any new source files will have their package lines updated to match the
| package we are in.
|
public void reload()
{
File subDirs[] = getPath().listFiles(new SubPackageFilter());
for (int i = 0; i < subDirs.length; i++) {
if (!JavaNames.isIdentifier(subDirs[i].getName()))
continue;
Target target;
synchronized (this)
{
target = targets.get(subDirs[i].getName());
}
if (target == null) {
Target newtarget = addPackage(subDirs[i].getName());
getEditor().findSpaceForVertex(newtarget);
}
}
Set<String> interestingSet = findTargets(getPath());
for (Iterator<String> it = interestingSet.iterator(); it.hasNext();) {
String targetName = it.next();
Target target;
synchronized (this)
{
target = targets.get(targetName);
}
if (target == null) {
Target newtarget = addClass(targetName);
if (getEditor() != null)
{
getEditor().findSpaceForVertex(newtarget);
}
}
}
List<Target> targetsCopy;
synchronized (this)
{
targetsCopy = targets.toList();
}
for (Target target : targetsCopy)
{
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
ct.analyseSource();
}
}
for (Target target : targetsCopy)
{
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
Class<?> cl = loadClass(ct.getQualifiedName());
if (cl != null) {
ct.determineRole(cl);
if (ct.upToDate()) {
ct.setState(State.COMPILED);
}
else {
ct.setState(State.NEEDS_COMPILE);
}
}
}
}
PackageEditor ed = getEditor();
if (ed != null)
ed.graphChanged();
}
| ReRead the pkg file and update the position of the targets in the graph
| @throws IOException
|
public void reReadGraphLayout() throws IOException
{
SortedProperties props = new SortedProperties();
synchronized (this)
{
packageFile.load(props);
}
int numTargets = 0;
try {
numTargets = Integer.parseInt(props.getProperty("package.numTargets", "0"));
}
catch (Exception e) {
synchronized (this)
{
Debug.printCallStack("Error loading from bluej package file " + packageFile + ": " + e);
}
return;
}
for (int i = 0; i < numTargets; i++) {
String identifierName = props.getProperty("target" + (i + 1) + ".name");
int x = Integer.parseInt(props.getProperty("target" + (i + 1) + ".x"));
int y = Integer.parseInt(props.getProperty("target" + (i + 1) + ".y"));
int height = Integer.parseInt(props.getProperty("target" + (i + 1) + ".height"));
int width = Integer.parseInt(props.getProperty("target" + (i + 1) + ".width"));
Target target = getTarget(identifierName);
if (target != null){
target.setPos(x, y);
target.setSize(width, height);
}
}
repaint();
}
@OnThread(Tag.Any)
public void repaint()
{
JavaFXUtil.runNowOrLater(() -> {
PackageEditor ed = getEditor();
if (ed != null) ed.repaint();
});
}
| Save this package to disk. The package is saved to the standard package
| file.
|
@OnThread(Tag.FXPlatform)
public synchronized void save(Properties frameProperties)
{
| create the directory if it doesn't exist
|
File dir = getPath();
if (!dir.exists()) {
if (!dir.mkdir()) {
Debug.reportError("Error creating directory " + dir);
return;
}
}
SortedProperties props = new SortedProperties();
props.putAll(frameProperties);
props.put("package.numDependencies", String.valueOf(usesArrows.size()));
int t_count = 0;
Iterator<Target> t_enum = targets.iterator();
while (t_enum.hasNext()){
Target t = t_enum.next();
if (t.isSaveable()) {
t.save(props, "target" + (t_count + 1));
t_count++;
}
}
props.put("package.numTargets", String.valueOf(t_count));
Target t = getTarget(ReadmeTarget.README_ID);
t.save(props, "readme");
for (int i = 0; i < usesArrows.size(); i++)
{
Dependency d = usesArrows.get(i);
d.save(props, "dependency" + (i + 1));
}
try {
packageFile.save(props);
}
catch (IOException e) {
Debug.reportError("Exception when saving package file : " + e);
return;
}
lastSavedProps = props;
}
| Import a source file into this package as a new class target. Returns an
| error code: NO_ERROR - everything is fine FILE_NOT_FOUND - file does not
| exist ILLEGAL_FORMAT - the file name does not end in ".java" CLASS_EXISTS -
|* a class with this name already exists COPY_ERROR - could not copy
*/
public int importFile(File aFile)
{
// check whether specified class exists and is a java file
|
|if (!aFile.exists())
|
|return FILE_NOT_FOUND;
|
|String fileName = aFile.getName();
|
|String className;
|
|if (fileName.endsWith("." + SourceType.Java.getExtension())) // it's a Java source file
className = fileName.substring(0, fileName.length() - SourceType.Java.getExtension().length() - 1);
else if (fileName.endsWith("." + SourceType.Stride.getExtension())) // it's a Stride source file
className = fileName.substring(0, fileName.length() - SourceType.Stride.getExtension().length() - 1);
else{ return ILLEGAL_FORMAT;
|
|}
|
|// check whether name is already used
|
|if (getTarget(className) != null)
|
|return CLASS_EXISTS;
|
|// copy class source into package
|
|File destFile = new File(getPath(), fileName);
|
|try {
|
|FileUtility.copyFile(aFile, destFile);
|
|}
|
|catch (IOException ioe) {
|
|return COPY_ERROR;
|
|}
|
|ClassTarget t = addClass(className);
|
|getEditor().findSpaceForVertex(t);
|
|t.analyseSource();
|
|DataCollector.addClass(this, t);
|
|return NO_ERROR;
|
|}
|
|public ClassTarget addClass(String className)
|
|{
|
|// create class icon (ClassTarget) for new class
|
|ClassTarget target = new ClassTarget(this, className);
|
|addTarget(target);
|
|// make package line in class source match our package
|
|try {
|
|target.enforcePackage(getQualifiedName());
|
|}
|
|catch (IOException ioe) {
|
|Debug.message(ioe.getLocalizedMessage());
|
|}
|
|return target;
|
|}
|
|/**
| Add a new package target to this package.
|
| @param packageName The basename of the package to add
|
public PackageTarget addPackage(String packageName)
{
PackageTarget target = new PackageTarget(this, packageName);
addTarget(target);
return target;
}
@OnThread(Tag.Any)
public Debugger getDebugger()
{
return getProject().getDebugger();
}
| Loads a class using the current project class loader.
| Return null if the class cannot be loaded.
|
public Class> loadClass(String className)
{
return getProject().loadClass(className);
}
@OnThread(Tag.Any)
public synchronized List getVertices()
{
List<Target> r = new ArrayList<>();
for (Target t : targets)
r.add(t);
return r;
}
| Return a List of all ClassTargets that have the role of a unit test.
|
public synchronized List getTestTargets()
{
List<ClassTarget> l = new ArrayList<ClassTarget>();
for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
Target target = it.next();
if (target instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) target;
if (ct.isUnitTest())
l.add(ct);
}
}
return l;
}
| Find and compile all uncompiled classes, and get reports of compilation
| status/results via the specified CompileObserver.
|
| In general this should be called only when the debugger is
| in the idle state (or at least not when executing user code). A new
| project classloader will be created which can be used to load the
| newly compiled classes, once they are ready.
|
| @param compObserver An observer to be notified of compilation progress.
| The callback methods will be called on the Swing EDT.
| The 'endCompile' method will always be called; other
| methods may not be called if the compilation is aborted
| (sources cannot be saved etc).
|
public void compile(FXCompileObserver compObserver, CompileReason reason, CompileType type)
{
Set<ClassTarget> toCompile = new HashSet<ClassTarget>();
try
{
List<ClassTarget> classTargets;
synchronized (this)
{
classTargets = getClassTargets();
}
for (ClassTarget ct : classTargets)
{
if (!ct.isCompiled() && !ct.isQueued())
{
ct.ensureSaved();
toCompile.add(ct);
ct.setQueued(true);
}
}
if (!toCompile.isEmpty())
{
if (type.keepClasses())
{
project.removeClassLoader();
project.newRemoteClassLoaderLeavingBreakpoints();
}
ArrayList<FXCompileObserver> observers = new ArrayList<>(compileObservers);
if (compObserver != null)
{
observers.add(compObserver);
}
doCompile(toCompile, new PackageCompileObserver(observers), reason, type);
}
else {
if (compObserver != null) {
compObserver.endCompile(new CompileInputFile[0], true, type, -1);
}
}
}
catch (IOException ioe) {
Debug.log("Error saving class before compile: " + ioe.getLocalizedMessage());
for (ClassTarget ct : toCompile) {
ct.setQueued(false);
}
if (compObserver != null) {
compObserver.endCompile(new CompileInputFile[0], false, type, -1);
}
}
}
| Find and compile all uncompiled classes.
|
| In general this should be called only when the debugger is
| in the idle state (or at least not when executing user code). A new
| project classloader will be created which can be used to load the
| newly compiled classes, once they are ready.
|
public void compile(CompileReason reason, CompileType type)
{
if (! currentlyCompiling) {
currentlyCompiling = true;
compile(new FXCompileObserver() {
@Override
@OnThread(Tag.FXPlatform)
public boolean compilerMessage(Diagnostic diagnostic, CompileType type)
{
return false;
}
@Override
@OnThread(Tag.FXPlatform)
public void startCompile(CompileInputFile[] sources, CompileReason reason, CompileType type, int compilationSequence)
{
}
@Override
@OnThread(Tag.FXPlatform)
public void endCompile(CompileInputFile[] sources, boolean succesful, CompileType type2, int compilationSequence)
{
currentlyCompiling = false;
if (queuedCompile) {
queuedCompile = false;
compile(queuedReason, type);
queuedReason = null;
}
}
}, reason, type);
}
else {
queuedCompile = true;
queuedReason = reason;
}
}
| Compile a single class.
|
public void compile(ClassTarget ct, CompileReason reason, CompileType type)
{
compile(ct, false, null, reason, type);
}
| Compile a single class.
|
public void compile(ClassTarget ct, boolean forceQuiet, FXCompileObserver compObserver, CompileReason reason, CompileType type)
{
if (!checkCompile()) {
return;
}
ClassTarget assocTarget = (ClassTarget) ct.getAssociation();
if (assocTarget != null && ! assocTarget.hasSourceCode()) {
assocTarget = null;
}
if (!ct.hasSourceCode()) {
ct = null;
}
if (ct != null || assocTarget != null) {
if (type.keepClasses())
{
project.removeClassLoader();
project.newRemoteClassLoaderLeavingBreakpoints();
}
if (ct != null) {
ArrayList<FXCompileObserver> chainedObservers = new ArrayList<>(compileObservers);
if (compObserver != null)
{
chainedObservers.add(compObserver);
}
FXCompileObserver observer;
if (forceQuiet) {
observer = new QuietPackageCompileObserver(chainedObservers);
}
else {
observer = new PackageCompileObserver(chainedObservers);
}
searchCompile(ct, observer, reason, type);
}
if (assocTarget != null) {
searchCompile(assocTarget, new QuietPackageCompileObserver(Collections.emptyList()), reason, type);
}
}
}
| Compile a single class quietly.
|
public void compileQuiet(ClassTarget ct, CompileReason reason, CompileType type)
{
if (!isDebuggerIdle()) {
return;
}
searchCompile(ct, new QuietPackageCompileObserver(Collections.emptyList()), reason, type);
}
| Force compile of all classes. Called by user function "rebuild".
|*/
public void rebuild()
{
if (!checkCompile()) {
return;
}
// Saving a class target can change its name; we need to copy the set of targets
// first, and iterate through the copied list, to avoid "concurrent" modification
// problems.
List<ClassTarget> compileTargets = new ArrayList<ClassTarget>();
synchronized (this)
{
for (Iterator<Target> it = targets.iterator(); it.hasNext(); )
|
|{
|
|Target target = it.next();
|
|if (target instanceof ClassTarget)
|
|{
|
|compileTargets.add((ClassTarget)target);
|
|}
|
|}
|
|}
|
|try {
|
|for (Iterator<ClassTarget> i = compileTargets.iterator(); i.hasNext(); ) {
|
|ClassTarget ct = i.next();
|
|// we don't want to try and compile if it is a class target without src
|
|if (ct.hasSourceCode()) {
|
|ct.ensureSaved();
|
|ct.markModified();
|
|ct.setQueued(true);
|
|}
|
|else {
|
|i.remove();
|
|}
|
|}
|
|if (!compileTargets.isEmpty())
|
|{
|
|project.removeClassLoader();
|
|project.newRemoteClassLoader();
|
|doCompile(compileTargets, new PackageCompileObserver(compileObservers), CompileReason.REBUILD, CompileType.EXPLICIT_USER_COMPILE);
|
|}
|
|}
|
|catch (IOException ioe) {
|
|showMessageWithText("file-save-error-before-compile", ioe.getLocalizedMessage());
}
}
/**
* Have all editors in this package save the file the are showing.
* Called when doing a cvs operation
*/
public void saveFilesInEditors() throws IOException
|
|{
|
|// Because we call editor.save() on targets, which can result in
|
|// a renamed class target, we need to iterate through a copy of
|
|// the collection - hence the new ArrayList call here:
|
|List<ClassTarget> classTargets;
|
|synchronized (this)
|
|{
|
|classTargets = new ArrayList<>(getClassTargets());
|
|}
|
|for (ClassTarget ct : classTargets) {
|
|Editor ed = ct.getEditor();
|
|// Editor can be null eg. class file and no src file
|
|if (ed != null) {
|
|ed.save();
|
|}
|
|}
|
|}
|
|/**
| Compile a class together with its dependencies, as necessary.
|
private void searchCompile(ClassTarget t, FXCompileObserver observer, CompileReason reason, CompileType type)
{
if (t.isQueued()) {
return;
}
Set<ClassTarget> toCompile = new HashSet<ClassTarget>();
try {
List<ClassTarget> queue = new LinkedList<ClassTarget>();
toCompile.add(t);
t.ensureSaved();
queue.add(t);
t.setQueued(true);
while (! queue.isEmpty()){
ClassTarget head = queue.remove(0);
for (Dependency d : head.dependencies()) {
if (!(d.getTo() instanceof ClassTarget)) {
continue;
}
ClassTarget to = (ClassTarget) d.getTo();
if (!to.isCompiled() && ! to.isQueued() && toCompile.add(to)) {
to.ensureSaved();
to.setQueued(true);
queue.add(to);
}
}
}
doCompile(toCompile, observer, reason, type);
}
catch (IOException ioe) {
Debug.log("Failed to save source before compile; " + ioe.getLocalizedMessage());
for (ClassTarget ct : toCompile) {
ct.setQueued(false);
}
}
}
| Compile every Target in 'targetList'. Every compilation goes through this method.
| All targets in the list should have been saved beforehand.
|
private void doCompile(Collection<ClassTarget> targetList, FXCompileObserver edtObserver, CompileReason reason, CompileType type)
{
CompileObserver observer = new EventqueueCompileObserverAdapter(new DataCollectionCompileObserverWrapper(project, edtObserver));
if (targetList.isEmpty()) {
return;
}
List<CompileInputFile> srcFiles = Utility.mapList(targetList, ClassTarget::getCompileInputFile);
if (srcFiles.size() > 0)
{
JobQueue.getJobQueue().addJob(srcFiles.toArray(new CompileInputFile[0]), observer, project.getClassLoader(), project.getProjectDir(),
! PrefMgr.getFlag(PrefMgr.SHOW_UNCHECKED), project.getProjectCharset(), reason, type);
}
}
| Returns true if the debugger is not busy. This is true if it is either
| IDLE, or has not been completely constructed (NOTREADY).
|
public boolean isDebuggerIdle()
{
Debugger debugger = getDebugger();
if (debugger == null) {
return true;
}
int status = debugger.getStatus();
return (status == Debugger.IDLE) || (status == Debugger.NOTREADY);
}
| Check whether it's okay to compile and display a message about it.
|
private boolean checkCompile()
{
if (isDebuggerIdle())
return true;
showMessage("compile-while-executing");
return false;
}
| Compile the package, but only when the debugger is in an idle state.
| @param specificTarget The single classtarget to compile; if null then will compile whole package.
|
public void compileOnceIdle(ClassTarget specificTarget, CompileReason reason, CompileType type)
{
if (! waitingForIdleToCompile) {
if (isDebuggerIdle())
{
if (specificTarget == null)
compile(reason, type);
else{ compile(specificTarget, reason, type);
}
}
else {
waitingForIdleToCompile = true;
DebuggerListener dlistener = new DebuggerListener() {
@Override
@OnThread(Tag.Any)
public void processDebuggerEvent(DebuggerEvent e, boolean skipUpdate)
{
if (e.getNewState() == Debugger.IDLE)
{
getDebugger().removeDebuggerListener(this);
Platform.runLater(() -> {
if (waitingForIdleToCompile) {
waitingForIdleToCompile = false;
compileOnceIdle(specificTarget, reason, type);
}
});
}
}
};
getDebugger().addDebuggerListener(dlistener);
if (isDebuggerIdle()) {
waitingForIdleToCompile = false;
compile(reason, type);
getDebugger().removeDebuggerListener(dlistener);
}
}
}
}
| Generate documentation for this package.
|
| @return "" if everything was alright, an error message otherwise.
|*/
public String generateDocumentation()
{
// This implementation currently just delegates the generation to
// the project this package is part of.
|
|return project.generateDocumentation();
|
|}
|
|/**
| Generate documentation for class in this ClassTarget.
|
| @param ct
| the class to generate docs for
|
public void generateDocumentation(ClassTarget ct)
{
String filename = ct.getSourceFile().getPath();
project.generateDocumentation(filename);
}
| Re-initialize breakpoints, necessary after a new class loader is
| installed.
|
public void reInitBreakpoints()
{
List<ClassTarget> classTargets;
synchronized (this)
{
classTargets = getClassTargets();
}
for (ClassTarget target : classTargets)
{
target.reInitBreakpoints();
}
}
| Remove all step marks in all classes.
|
public void removeStepMarks()
{
List<ClassTarget> classTargets;
synchronized (this)
{
classTargets = new ArrayList<>(getClassTargets());
}
for (ClassTarget target : classTargets)
{
target.removeStepMark();
}
if (getUI() != null)
{
getUI().highlightObject(null);
}
}
public synchronized void addTarget(Target t)
{
if (t.getPackage() != this)
throw new IllegalArgumentException();
targets.add(t.getIdentifierName(), t);
fireChangedEvent();
}
public synchronized void removeTarget(Target t)
{
targets.remove(t.getIdentifierName());
t.setRemoved();
fireChangedEvent();
}
| Changes the Target identifier. Targets are stored in a hashtable with
| their name as the key. If class name changes we need to remove the target
| and add again with the new key.
|
public synchronized void updateTargetIdentifier(Target t, String oldIdentifier, String newIdentifier)
{
if (t == null || newIdentifier == null) {
Debug.reportError("cannot properly update target name...");
return;
}
targets.remove(oldIdentifier);
targets.add(newIdentifier, t);
}
| Remove the arrow representing the given dependency
|
| @param d the dependency to remove
|
@OnThread(Tag.FXPlatform)
public void removeArrow(Dependency d)
{
if (!(d instanceof UsesDependency))
{
userRemoveDependency(d);
}
removeDependency(d, true);
getEditor().graphChanged();
}
| A user initiated addition of an "implements" clause from a class to
|* an interface
*
* @pre d.getFrom() and d.getTo() are both instances of ClassTarget
*/
public void userAddImplementsClassDependency(ClassTarget from, ClassTarget to)
{
ClassInfo info = from.getSourceInfo().getInfo(from.getJavaSourceFile(), this);
|
|if (info != null) {
|
|from.getEditor().addImplements(to.getBaseName(), info);
|
|from.analyseSource();
|
|}
|
|}
|
|/**
| A user initiated addition of an "extends" clause from an interface to
|* an interface
*
* @pre d.getFrom() and d.getTo() are both instances of ClassTarget
*/
public void userAddExtendsInterfaceDependency(ClassTarget from, ClassTarget to)
|
|{
|
|ClassInfo info = from.getSourceInfo().getInfo(from.getJavaSourceFile(), this);
|
|from.getEditor().addExtendsInterface(to.getBaseName(), info);
|
|from.analyseSource();
|
|}
|
|/**
| A user initiated addition of an "extends" clause from a class to
|* a class
*
* @pre d.getFrom() and d.getTo() are both instances of ClassTarget
*/
public void userAddExtendsClassDependency(ClassTarget from, ClassTarget to)
{
from.getEditor().setExtendsClass(to.getBaseName(), from.getSourceInfo().getInfo(from.getJavaSourceFile(), this));
|
|from.analyseSource();
|
|}
|
|/**
| A user initiated removal of a dependency
|
| @param d an instance of an Implements or Extends dependency
|
public void userRemoveDependency(Dependency d)
{
if (!(d.getFrom() instanceof ClassTarget) || !(d.getTo() instanceof ClassTarget))
return;
ClassTarget from = (ClassTarget) d.getFrom();
ClassTarget to = (ClassTarget) d.getTo();
ClassInfo info = from.getSourceInfo().getInfo(from.getJavaSourceFile(), this);
if (d instanceof ImplementsDependency) {
from.getEditor().removeExtendsOrImplementsInterface(to.getBaseName(), info);
}
p.public else if(d instanceof ExtendsDependency)
{
from.getEditor().removeExtendsClass(info);
}
}
| Lay out the arrows between targets.
|
@OnThread(Tag.FXPlatform)
private void recalcArrows()
{
for (Target t : getVertices())
{
if (t instanceof DependentTarget) {
DependentTarget dt = (DependentTarget) t;
dt.recalcInUses();
dt.recalcOutUses();
}
}
}
| Return the target with name "identifierName".
|*
* @param identifierName
* the unique name of a target.
* @return the target with name "tname" if existent, null otherwise.
*/
@OnThread(Tag.Any)
public synchronized Target getTarget(String identifierName)
{
if (identifierName == null)
return null;
Target t = targets.get(identifierName);
|
|return t;
|
|}
|
|/**
| Return the dependent target with name "identifierName".
|*
* @param identifierName
* the unique name of a target.
* @return the target with name "tname" if existent and if it is a
* DependentTarget, null otherwise.
*/
public synchronized DependentTarget getDependentTarget(String identifierName)
{
if (identifierName == null)
|
|return null;
|
|Target t = targets.get(identifierName);
|
|if (t instanceof DependentTarget)
|
|return (DependentTarget) t;
|
|return null;
|
|}
|
|/**
| Returns an ArrayList of ClassTargets holding all targets of this package.
| @return a not null but possibly empty array list of ClassTargets for this package.
|
@OnThread(Tag.Any)
public synchronized final ArrayList getClassTargets()
{
ArrayList<ClassTarget> risul = new ArrayList<ClassTarget>();
for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
Target target = it.next();
if (target instanceof ClassTarget) {
risul.add((ClassTarget) target);
}
}
return risul;
}
| Return a List of Strings with names of all classes in this package.
|
public synchronized List getAllClassnames()
{
return Utility.mapList(getClassTargets(), ClassTarget::getBaseName);
}
| Return a List of Strings with names of all classes in this package that
| has accompanying source.
|
public synchronized List getAllClassnamesWithSource()
{
List<String> names = new ArrayList<String>();
for (Iterator<Target> it = targets.iterator(); it.hasNext();) {
Target t = it.next();
if (t instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) t;
if (ct.hasSourceCode())
names.add(ct.getBaseName());
}
}
return names;
}
| Test whether a file instance denotes a BlueJ or Greenfoot package directory depending on which mode we are in.
|
| @param f
| the file instance that is tested for denoting a BlueJ package.
| @return true if f denotes a directory and a BlueJ package.
|
@OnThread(Tag.Any)
public static boolean isPackage(File f)
{
if (Config.isGreenfoot())
return GreenfootProjectFile.exists(f);
else{ return BlueJPackageFile.exists(f);
}
}
| Test whether this name is the name of a package file.
|
@OnThread(Tag.Any)
public static boolean isPackageFileName(String name)
{
if (Config.isGreenfoot())
return GreenfootProjectFile.isProjectFileName(name);
else{ return BlueJPackageFile.isPackageFileName(name);
}
}
| Called when in an interesting state (e.g. adding a new dependency) and a
| target is selected. Calling with 'null' as parameter resets to idle state.
|
@OnThread(Tag.Any)
public void targetSelected(Target t)
{
|
|
|if(t == null) {}if(getState() != S_IDLE) {}setState(S_IDLE);
|
|setStatus(" ");
}
return;
}
switch(getState()) {} case S_CHOOSE_USES_FROM :
if (t instanceof DependentTarget) {}fromChoice = (DependentTarget) t;
setState(S_CHOOSE_USES_TO);
|
|setStatus(chooseUsesTo);
|
|}
|
|else {}setState(S_IDLE);
|
|setStatus(" ");
}
break;
case S_CHOOSE_USES_TO :
if (t != fromChoice && t instanceof DependentTarget) {}setState(S_IDLE);
addDependency(new UsesDependency(this, fromChoice, (DependentTarget) t), true);
|
|setStatus(" ");
}
break;
case S_CHOOSE_EXT_FROM :
if (t instanceof DependentTarget) {}fromChoice = (DependentTarget) t;
setState(S_CHOOSE_EXT_TO);
setStatus(chooseInhTo);
}
|
|else {}setState(S_IDLE);
|
|setStatus(" ");
}
break;
case S_CHOOSE_EXT_TO :
if (t != fromChoice) {}setState(S_IDLE);
if (t instanceof ClassTarget && fromChoice instanceof ClassTarget) {}
ClassTarget from = (ClassTarget) fromChoice;
|
|ClassTarget to = (ClassTarget) t;
|
|// if the target is an interface then we have an
|
|// implements dependency
|
|if (to.isInterface()) {} Dependency d = new ImplementsDependency(this, from, to);
|
|if (from.isInterface()) {}userAddImplementsInterfaceDependency(d);
|
|}
|
|else {}userAddImplementsClassDependency(d);
|
|}
|
|addDependency(d, true);
|
|}
|
|else {} // an extends dependency can only be from a class to
|
|// another class
|
|if (!from.isInterface() && !to.isEnum() && !from.isEnum()) {} Dependency d = new ExtendsDependency(this, from, to);
|
|userAddExtendsClassDependency(d);
|
|addDependency(d, true);
|
|}
|
|else {} // TODO display an error dialog or status
|
|}
|
|}
|
|}
|
|setStatus(" ");
}
break;
default :
// e.g. deleting arrow - selecting target ignored
break;
}
*/
}
/**
* Use the dialog manager to display an error message. The PkgMgrFrame is
| used to find a parent window so we can correctly offset the dialog.
|
public void showError(String msgId)
{
PkgMgrFrame.showError(this, msgId);
}
| Use the dialog manager to display a message. The PkgMgrFrame is used to
| find a parent window so we can correctly offset the dialog.
|
public void showMessage(String msgId)
{
PkgMgrFrame.showMessage(this, msgId);
}
| Use the dialog manager to display a message with text. The PkgMgrFrame is
| used to find a parent window so we can correctly offset the dialog.
|
public void showMessageWithText(String msgId, String text)
{
PkgMgrFrame.showMessageWithText(this, msgId, text);
}
| Don't remember the last shown source anymore.
|
public void forgetLastSource()
{
lastSourceName = "";
}
| A thread has hit a breakpoint, done a step or selected a frame in the debugger. Display the source
| code with the relevant line highlighted.
|
| Note: source name is the unqualified name of the file (no path attached)
|
| @return true if the debugger display is already taken care of, or
| false if you still want to show the ExecControls window afterwards.
|
private boolean showSource(DebuggerThread thread, String sourcename, int lineNo, ShowSourceReason reason, String msg)
{
boolean bringToFront = !sourcename.equals(lastSourceName);
lastSourceName = sourcename;
Editor targetEditor = editorForTarget(new File(getPath(), sourcename).getAbsolutePath(), bringToFront);
if (targetEditor != null) {
DebuggerObject currentObject = thread.getCurrentObject(0);
if (getUI() != null)
{
getUI().highlightObject(currentObject);
}
return targetEditor.setStepMark(lineNo, msg, reason.isSuspension(), thread);
}
else if (reason == ShowSourceReason.BREAKPOINT_HIT) {
showMessageWithText("break-no-source", sourcename);
}
return false;
}
| Show the specified line of the specified source file. Open the editor if necessary.
| @param sourcename The source file to show
| @param lineNo The line number to show
| @return true if the editor was the most recent editor to have a message displayed
|
public void showSource(String sourcename, int lineNo)
{
String msg = " ";
boolean bringToFront = !sourcename.equals(lastSourceName);
lastSourceName = sourcename;
showEditorMessage(new File(getPath(), sourcename).getPath(), lineNo, msg, false, bringToFront);
}
| An interface for message "calculators" which can produce enhanced diagnostic messages when
|* given a reference to the editor in which a compilation error occurred.
*/
public static interface MessageCalculator
{
/**
* Produce a diagnostic message for the given editor.
| This should produce something half-way helpful if null is passed.
|
| @param e The editor where the original error occurred (null if it cannot be determined).
|
public String calculateMessage(Editor e);
}
| Attempt to display (in the corresponding editor) an error message associated with a
| specific line in a class. This is done by opening the class's source, highlighting the line
| and showing the message in the editor's information area. If the filename specified does
| not exist, the message is not shown.
|
| @return true if the message was displayed; false if there was no suitable class.
|
private boolean showEditorMessage(String filename, int lineNo, final String message,
boolean beep, boolean bringToFront)
{
Editor targetEditor = editorForTarget(filename, bringToFront);
if (targetEditor == null)
{
Debug.message("Error or exception for source not in project: " + filename + ", line " +
lineNo + ": " + message);
return false;
}
targetEditor.displayMessage(message, lineNo, 0);
return true;
}
| Find or open the Editor for a given source file. The editor is opened and displayed if it is not
| currently visible. If the source file is in another package, a package editor frame will be
| opened for that package.
|
| @param filename The source file name, which should be a full absolute path
| @param bringToFront True if the editor should be brought to the front of the window z-order
| @return The editor for the given source file, or null if there is no editor.
|
private Editor editorForTarget(String filename, boolean bringToFront)
{
Target t = getTargetForSource(filename);
if (! (t instanceof ClassTarget)) {
return null;
}
ClassTarget ct = (ClassTarget) t;
Editor targetEditor = ct.getEditor();
if (targetEditor != null) {
if (! targetEditor.isOpen() || bringToFront) {
ct.open();;
}
}
return targetEditor;
}
| Find the target for a given source file. If the target is in another package, a package editor
| frame is opened for the package (if not open already).
|
| @param filename The source file name
| @return The corresponding target, or null if the target doesn't exist.
|
private Target getTargetForSource(String filename)
{
String fullName = getProject().convertPathToPackageName(filename);
if (fullName == null) {
return null;
}
String packageName = JavaNames.getPrefix(fullName);
String className = JavaNames.getBase(fullName);
Target t = null;
if (! packageName.equals(getQualifiedName())) {
Package pkg = getProject().getPackage(packageName);
if (pkg != null) {
PkgMgrFrame pmf = PkgMgrFrame.findFrame(pkg);
if (pmf == null) {
pmf = PkgMgrFrame.createFrame(pkg, null);
}
pmf.setVisible(true);
t = pkg.getTarget(className);
}
}
else {
t = getTarget(className);
}
return t;
}
| An enumeration for indicating whether a compilation diagnostic was actually displayed to the
| user.
|
private static enum ErrorShown
{
ERROR_SHOWN, ERROR_NOT_SHOWN, EDITOR_NOT_FOUND
}
| Display a compiler diagnostic (error or warning) in the appropriate editor window.
|
| @param diagnostic The diagnostic to display
| @param messageCalc The message "calculator", which returns a modified version of the message;
|* may be null, in which case the original message is shown unmodified.
* @param errorIndex The index of the error (first is 0, second is 1, etc)
| @param compileType The type of the compilation which caused the error.
|
private ErrorShown showEditorDiagnostic(Diagnostic diagnostic, MessageCalculator messageCalc, int errorIndex, CompileType compileType)
{
String fileName = diagnostic.getFileName();
if (fileName == null) {
return ErrorShown.EDITOR_NOT_FOUND;
}
Target target = getTargetForSource(fileName);
if (! (target instanceof ClassTarget)) {
return ErrorShown.EDITOR_NOT_FOUND;
}
ClassTarget t = (ClassTarget) target;
Editor targetEditor = t.getEditor();
if (targetEditor != null) {
if (messageCalc != null) {
diagnostic.setMessage(messageCalc.calculateMessage(targetEditor));
}
if (project.isClosing()) {
return ErrorShown.ERROR_NOT_SHOWN;
}
boolean shown = t.showDiagnostic(diagnostic, errorIndex, compileType);
return shown ? ErrorShown.ERROR_SHOWN : ErrorShown.ERROR_NOT_SHOWN;
}
else {
Debug.message(t.getDisplayName() + ", line" + diagnostic.getStartLine() +
": " + diagnostic.getMessage());
return ErrorShown.EDITOR_NOT_FOUND;
}
}
| A breakpoint in this package was hit.
|
public void hitBreakpoint(DebuggerThread thread)
{
String msg = null;
if (PrefMgr.getFlag(PrefMgr.ACCESSIBILITY_SUPPORT)) {
msg = Config.getString("debugger.accessibility.breakpoint");
msg = msg.replace("$", thread.getName());
}
if (!showSource(thread, thread.getClassSourceName(0), thread.getLineNumber(0), ShowSourceReason.BREAKPOINT_HIT, msg))
{
getProject().getExecControls().show();
getProject().getExecControls().selectThread(thread);
}
}
| Execution stopped by someone pressing the "halt" button or we have just
|* done a "step".
*/
public void hitHalt(DebuggerThread thread)
{
boolean breakpoint = thread.isAtBreakpoint();
String msg = null;
if (PrefMgr.getFlag(PrefMgr.ACCESSIBILITY_SUPPORT)) {
msg = breakpoint ? Config.getString("debugger.accessibility.breakpoint") : Config.getString("debugger.accessibility.paused");
msg = msg.replace("$", thread.getName());
}
int frame = thread.getSelectedFrame();
ShowSourceReason reason = breakpoint ? ShowSourceReason.BREAKPOINT_HIT : ShowSourceReason.STEP_OR_HALT;
|
|if (!showSource(thread, thread.getClassSourceName(frame), thread.getLineNumber(frame), reason, msg))
|
|{
|
|getProject().getExecControls().show();
|
|getProject().getExecControls().selectThread(thread);
|
|}
|
|}
|
|/**
| Display a source file from this package at the specified position.
|
public void showSourcePosition(DebuggerThread thread, String sourceName, int lineNumber)
{
showSource(thread, sourceName, lineNumber, ShowSourceReason.FRAME_SELECTED, null);
}
| Display an exception message. This is almost the same as "errorMessage"
|* except for different help texts.
*/
public void exceptionMessage(ExceptionDescription exception)
{
String text = exception.getClassName();
if (text == null) {
reportException(exception.getText());
|
|return;
|
|}
|
|String message = text + ":\n" + exception.getText();
List<SourceLocation> stack = exception.getStack();
if ((stack == null) || (stack.size() == 0)) {
// Stack empty or missing. This can happen when an exception is
|
|// thrown from the code pad for instance.
|
|return;
|
|}
|
|// using the stack, try to find the source code
|
|boolean done = false;
|
|Iterator<SourceLocation> iter = stack.iterator();
|
|boolean firstTime = true;
|
|while (!done && iter.hasNext()){
|
|SourceLocation loc = iter.next();
|
|String locFileName = loc.getFileName();
|
|if (locFileName != null) {
|
|String filename = new File(getPath(), locFileName).getPath();
|
|int lineNo = loc.getLineNumber();
|
|done = showEditorMessage(filename, lineNo, message, true, true);
|
|if (firstTime && !done) {
|
|message += " (in " + loc.getClassName() + ")";
firstTime = false;
}
}
}
if (!done) {
SourceLocation loc = stack.get(0);
showMessageWithText("error-in-file", loc.getClassName() + ":" + loc.getLineNumber() + "\n" + message);
}
}
/**
* Displays the given class at the given line number (due to an exception, usually clicked-on stack trace).
*
* Simpler than the other exceptionMessage method because it requires less details
public void exceptionMessage(String className, int lineNumber)
{
showEditorMessage(className, lineNumber, "", false, true);
}
| Report an execption. Usually, we do this through "errorMessage", but if
|* we cannot make sense of the message format, and thus cannot figure out
* class name and line number, we use this way.
*/
public void reportException(String text)
{
showMessageWithText("exception-thrown", text);
}
/**
* Use the resource name in order to return the path of the jar file
* containing the given resource.
* <p>
* If it is not in a jar file it returns the original resource path
| (URL).
|
| @param c The class to get the path to
| @return A string indicating the path of the jar file (if applicable
| and if not, it returns the path/URL to the resource)
|
protected static String getResourcePath(Class<?> c)
{
URL srcUrl = c.getResource(c.getSimpleName()+".class");
try {
if (srcUrl != null) {
if (srcUrl.getProtocol().equals("file")) {
File srcFile = new File(srcUrl.toURI());
return srcFile.toString();
}
if (srcUrl.getProtocol().equals("jar")){
int classIndex = srcUrl.toString().indexOf("!");
String subUrl = srcUrl.toString().substring(4, classIndex);
if (subUrl.startsWith("file:")) {
return new File(new URI(subUrl)).toString();
}
if (classIndex!=-1){
return srcUrl.toString().substring(4, classIndex);
}
}
}
else {
return null;
}
}
catch (URISyntaxException uriSE) {
}
return srcUrl.toString();
}
| Check whether a loaded class was actually loaded from the specified class file
| @param c The loaded class
| @param f The class file to check against (should be a compiled .class file)
| @return True if the class was loaded from the specified file; false otherwise
|
public static boolean checkClassMatchesFile(Class<?> c, File f)
{
try {
URL srcUrl = c.getResource(c.getSimpleName()+".class");
if (srcUrl == null) {
return true;
}
if (srcUrl != null && srcUrl.getProtocol().equals("file")) {
File srcFile = new File(srcUrl.toURI());
if (! f.equals(srcFile)) {
return false;
}
}
else {
return false;
}
}
catch (URISyntaxException uriSE) {
}
return true;
}
| Observe compilation jobs and change the PkgMgr interface elements as
| compilation goes through different stages, but don't display the popups
| for error/warning messages.
| Also relay compilation events to any listening extensions.
|
private class QuietPackageCompileObserver
implements FXCompileObserver
{
protected List<FXCompileObserver> chainedObservers;
| Construct a new QuietPackageCompileObserver. The chained observers (if
| non-empty list) are notified about each event.
|
public QuietPackageCompileObserver(List<FXCompileObserver> chainedObservers)
{
this.chainedObservers = new ArrayList<>(chainedObservers);
}
private void markAsCompiling(CompileInputFile[] sources, int compilationSequence)
{
for (int i = 0; i < sources.length; i++) {
String fileName = sources[i].getJavaCompileInputFile().getPath();
String fullName = getProject().convertPathToPackageName(fileName);
if (fullName != null) {
Target t = getTarget(JavaNames.getBase(fullName));
if (t instanceof ClassTarget) {
ClassTarget ct = (ClassTarget) t;
ct.markCompiling(compilationSequence);
}
}
}
}
private void sendEventToExtensions(String filename, int [] errorPosition, String message, int eventType, CompileType type)
{
File [] sources;
if (filename != null) {
sources = new File[1];
sources[0] = new File(filename);
}
else {
sources = new File[0];
}
CompileEvent aCompileEvent = new CompileEvent(eventType, type.keepClasses(), sources);
aCompileEvent.setErrorPosition(errorPosition);
aCompileEvent.setErrorMessage(message);
ExtensionsManager.getInstance().delegateEvent(aCompileEvent);
}
| A compilation has been started. Mark the affected classes as being
| currently compiled.
|
@Override
public void startCompile(CompileInputFile[] sources, CompileReason reason, CompileType type, int compilationSequence)
{
CompileEvent aCompileEvent = new CompileEvent(CompileEvent.COMPILE_START_EVENT, type.keepClasses(), Utility.mapList(Arrays.asList(sources), CompileInputFile::getJavaCompileInputFile).toArray(new File[0]));
ExtensionsManager.getInstance().delegateEvent(aCompileEvent);
if (type.keepClasses())
{
setStatus(compiling);
}
markAsCompiling(sources, compilationSequence);
for (FXCompileObserver chainedObserver : chainedObservers)
{
chainedObserver.startCompile(sources, reason, type, compilationSequence);
}
}
@Override
public boolean compilerMessage(Diagnostic diagnostic, CompileType type)
{
int [] errorPosition = new int[4];
errorPosition[0] = (int) diagnostic.getStartLine();
errorPosition[1] = (int) diagnostic.getStartColumn();
errorPosition[2] = (int) diagnostic.getEndLine();
errorPosition[3] = (int) diagnostic.getEndColumn();
if (diagnostic.getType() == Diagnostic.ERROR) {
errorMessage(diagnostic.getFileName(), errorPosition, diagnostic.getMessage(), type);
}
else {
warningMessage(diagnostic.getFileName(), errorPosition, diagnostic.getMessage(), type);
}
boolean shown = false;
for (FXCompileObserver chainedObserver : chainedObservers)
{
boolean s = chainedObserver.compilerMessage(diagnostic, type);
shown = shown || s;
}
return shown;
}
private void errorMessage(String filename, int [] errorPosition, String message, CompileType type)
{
sendEventToExtensions(filename, errorPosition, message, CompileEvent.COMPILE_ERROR_EVENT, type);
}
private void warningMessage(String filename, int [] errorPosition, String message, CompileType type)
{
sendEventToExtensions(filename, errorPosition, message, CompileEvent.COMPILE_WARNING_EVENT, type);
}
| Compilation has ended. Mark the affected classes as being normal
| again.
|
@Override
public void endCompile(CompileInputFile[] sources, boolean successful, CompileType type, int compilationSequence)
{
List<ClassTarget> targetsToAnalyse = new ArrayList<>();
List<ClassTarget> readyToCompileList = new ArrayList<>();
for (int i = 0; i < sources.length; i++) {
String filename = sources[i].getJavaCompileInputFile().getPath();
String fullName = getProject().convertPathToPackageName(filename);
if (fullName == null) {
continue;
}
ClassTarget t = (ClassTarget) targets.get(JavaNames.getBase(fullName));
if (t == null) {
continue;
}
t.markCompiled(successful, type);
if (t.getState() == State.COMPILED)
{
targetsToAnalyse.add(t);
}
else
{
if (t.getState() == State.NEEDS_COMPILE && type == CompileType.EXPLICIT_USER_COMPILE)
{
if (!checkDependecyCompilationError(t))
{
readyToCompileList.add(t);
}
}
}
t.setQueued(false);
if (t.isCompiled())
{
Class<?> c = loadClass(getQualifiedName(t.getIdentifierName()));
if (c!=null){
if (! checkClassMatchesFile(c, t.getClassFile())) {
String conflict=Package.getResourcePath(c);
String ident = t.getIdentifierName()+":";
DialogManager.showMessageWithPrefixTextFX(null, "compile-class-library-conflict", ident, conflict);
}
}
|
| compute ctxt files (files with comments and parameters
| names)
|
try {
ClassInfo info = t.getSourceInfo().getInfo(t.getJavaSourceFile(), t.getPackage());
if (info != null) {
OutputStream out = new FileOutputStream(t.getContextFile());
info.getComments().store(out, "BlueJ class context");
out.close();
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
doCompile(readyToCompileList, this, CompileReason.USER, CompileType.EXPLICIT_USER_COMPILE);
for (ClassTarget classTarget : targetsToAnalyse)
{
classTarget.analyseAfterCompile();
}
if (type.keepClasses())
{
setStatus(compileDone);
}
fireChangedEvent();
int eventId = successful ? CompileEvent.COMPILE_DONE_EVENT : CompileEvent.COMPILE_FAILED_EVENT;
CompileEvent aCompileEvent = new CompileEvent(eventId, type.keepClasses(), Utility.mapList(Arrays.asList(sources), CompileInputFile::getJavaCompileInputFile).toArray(new File[0]));
ExtensionsManager.getInstance().delegateEvent(aCompileEvent);
for (FXCompileObserver chainedObserver : chainedObservers)
{
chainedObserver.endCompile(sources, successful, type, compilationSequence);
}
}
}
private static class MisspeltMethodChecker
implements MessageCalculator
{
private static final int MAX_EDIT_DISTANCE = 2;
private final String message;
private int lineNumber;
private int column;
private Project project;
public MisspeltMethodChecker(String message, int column, int lineNumber, Project project)
{
this.message = message;
this.column = column;
this.lineNumber = lineNumber;
this.project = project;
}
private static String chopAtOpeningBracket(String name)
{
int openingBracket = name.indexOf('(');
if (openingBracket >= 0)
return name.substring(0,openingBracket);
else{ return name;
}
}
private String getLine(TextEditor e)
{
return e.getText(new bluej.parser.SourceLocation(lineNumber, 1), new bluej.parser.SourceLocation(lineNumber, e.getLineLength(lineNumber-1)));
}
private int getLineStart(TextEditor e)
{
return e.getOffsetFromLineColumn(new bluej.parser.SourceLocation(lineNumber, 1));
}
@Override
public String calculateMessage(Editor e0)
{
if (e0 == null) {
return message;
}
TextEditor e = e0.assumeText();
String missing = chopAtOpeningBracket(message.substring(message.lastIndexOf(' ') + 1));
ParsedCUNode pcuNode = e.getParsedNode();
if (pcuNode == null) {
return message;
}
int pos = convertColumn(getLine(e), column) + getLineStart(e);
TreeSet<String> maybeTheyMeant = new TreeSet<>();
ExpressionTypeInfo suggests = pcuNode.getExpressionType(pos, e.getSourceDocument());
AssistContent[] values = ParseUtils.getPossibleCompletions(suggests, project.getJavadocResolver(), null);
if (values != null) {
for (AssistContent a : values) {
String name = a.getName();
if (a.getKind() == CompletionKind.METHOD && Utility.editDistance(name.toLowerCase(), missing.toLowerCase()) <= MAX_EDIT_DISTANCE) {
maybeTheyMeant.add(a.getName());
}
}
}
if (maybeTheyMeant.isEmpty()) {
return message;
}
else {
String augmentedMessage = message + "; maybe you meant: " + maybeTheyMeant.pollFirst();
for (String sugg : maybeTheyMeant) {
augmentedMessage += " or " + sugg;
}
return augmentedMessage;
}
}
| Convert a column where a tab is counted as 8 to a column where a tab is counted
| as 1
|
private static int convertColumn(String string, int column)
{
int ccount = 0;
public defVis int lpos = 0;
int tabIndex = string.indexOf('\t');
while (tabIndex != -1 && lpos < column - 1){
lpos += tabIndex - ccount;
ccount = tabIndex;
if (lpos >= column - 1) {
break;
}
lpos = ((lpos + 8) / 8) * 8;
ccount += 1;
tabIndex = string.indexOf('\t', ccount);
}
ccount += column - lpos;
return ccount;
}
}
| The same, but also display error/warning messages for the user
|
private class PackageCompileObserver
extends QuietPackageCompileObserver
{
private int numErrors = 0;
| Construct a new PackageCompileObserver. The chained observer (if specified)
| is notified when the compilation ends.
|
public PackageCompileObserver(List<FXCompileObserver> chainedObservers)
{
super(chainedObservers);
}
@Override
public void startCompile(CompileInputFile[] sources, CompileReason reason, CompileType type, int compilationSequence)
{
numErrors = 0;
super.startCompile(sources, reason, type, compilationSequence);
}
@Override
public boolean compilerMessage(Diagnostic diagnostic, CompileType type)
{
super.compilerMessage(diagnostic, type);
if (diagnostic.getType() == Diagnostic.ERROR) {
return errorMessage(diagnostic, type);
}
else {
return warningMessage(diagnostic.getFileName(), (int) diagnostic.getStartLine(),
diagnostic.getMessage());
}
}
| Display an error message associated with a specific line in a class.
| This is done by opening the class's source, highlighting the line and
| showing the message in the editor's information area.
|
private boolean errorMessage(Diagnostic diagnostic, CompileType type)
{
numErrors += 1;
ErrorShown messageShown;
if (diagnostic.getFileName() == null)
{
showMessageWithText("compiler-error", diagnostic.getMessage());
return true;
}
String message = diagnostic.getMessage();
if (message.contains("cannot find symbol") && message.contains("method")) {
messageShown = showEditorDiagnostic(diagnostic,
new MisspeltMethodChecker(message,
(int) diagnostic.getStartColumn(),
(int) diagnostic.getStartLine(),
project), numErrors - 1, type);
}
else
{
messageShown = showEditorDiagnostic(diagnostic, null, numErrors - 1, type);
}
switch (messageShown)
{
case EDITOR_NOT_FOUND:
showMessageWithText("error-in-file", diagnostic.getFileName() + ":" +
diagnostic.getStartLine() + "\n" + message);
return true;
case ERROR_SHOWN:
return true;
default:
return false;
}
}
| Display a warning message: just a dialog box
| The dialog accumulates messages until reset() is called, which is
| done in the methods which the user can invoke to cause compilation
| Thus all the warnings caused by a "compilation" can be accumulated
|* into a single dialog.
* If searchCompile() built a single list, we wouldn't need to do this
*/
private boolean warningMessage(String filename, int lineNo, String message)
|
|{
|
|return true;
|
|}
|
|}
|
|// ---- end of bluej.compiler.CompileObserver interfaces ----
|
|/**
| closeAllEditors - closes all currently open editors within package Should
| be run whenever a package is removed from PkgFrame.
|
public void closeAllEditors()
{
List<Target> targetsCopy;
synchronized (this)
{
targetsCopy = new ArrayList<>();
for (Target t : targets)
targetsCopy.add(t);
}
for (Target target : targetsCopy) {
if (target instanceof EditableTarget) {
EditableTarget et = (EditableTarget) target;
if (et.editorOpen()) {
et.getEditor().close();
}
}
}
}
| Get history of invocation calls
|
| @return CallHistory object
|
public CallHistory getCallHistory()
{
return callHistory;
}
| String representation for debugging.
|
public String toString()
{
return "Package:" + getQualifiedName();
}
public SourceType getDefaultSourceType()
{
if (getClassTargets().stream().anyMatch(c -> c.getSourceType() == SourceType.Stride))
return SourceType.Stride;
else{ return SourceType.Java;
}
}
public void addDependency(Dependency dependency)
{
addDependency(dependency, dependency instanceof UsesDependency);
}
public void addDependency(Dependency d, boolean recalc)
{
DependentTarget from = d.getFrom();
DependentTarget to = d.getTo();
if (from == null || to == null)
{
return;
}
if (d instanceof UsesDependency)
{
if (usesArrows.contains(d))
{
return;
}
else
{
usesArrows.add((UsesDependency) d);
}
}
else
{
if (extendsArrows.contains(d))
{
return;
}
else
{
extendsArrows.add(d);
}
}
DependentTarget from1 = d.getFrom();
DependentTarget to1 = d.getTo();
from1.addDependencyOut(d, recalc);
to1.addDependencyIn(d, recalc);
DependencyEvent event = new DependencyEvent(d, this, DependencyEvent.Type.DEPENDENCY_ADDED);
ExtensionsManager.getInstance().delegateEvent(event);
}
public void removeDependency(Dependency dependency, boolean recalc)
{
if (dependency instanceof UsesDependency)
{
usesArrows.remove(dependency);
}
else
{
extendsArrows.remove(dependency);
}
DependentTarget from = dependency.getFrom();
DependentTarget to = dependency.getTo();
from.removeDependencyOut(dependency, recalc);
to.removeDependencyIn(dependency, recalc);
DependencyEvent event = new DependencyEvent(dependency, this, DependencyEvent.Type.DEPENDENCY_REMOVED);
ExtensionsManager.getInstance().delegateEvent(event);
}
| Call the given method or constructor.
|
public void callStaticMethodOrConstructor(CallableView view)
{
ui.callStaticMethodOrConstructor(view);
}
| Add an observer to listen to all compilations of this package.
|
public void addCompileObserver(FXCompileObserver fxCompileObserver)
{
compileObservers.add(fxCompileObserver);
}
| Checks if the class target has dependencies that have compilation errors
| @param classTarget the class target whom direct/indirect dependencies will be checked
| @return true if any of the dependencies or their ancestors have a compilation error
| otherwise it returns false
|
public boolean checkDependecyCompilationError(ClassTarget classTarget)
{
boolean dependencyError = false;
outerloop:
for (Dependency d : classTarget.dependencies())
{
ClassTarget dependent = (ClassTarget) d.getTo();
if (dependent.getState() == State.HAS_ERROR && dependent.hasSourceCode())
{
dependencyError = true;
break outerloop;
}
else
{
List<Dependency> dependencyParents = dependent.getParents();
dependencyError = dependencyParents.stream()
.filter(pv -> pv.getTo().getState() == State.HAS_ERROR)
.findFirst().isPresent();
if (dependencyError)
{
break outerloop;
}
for (Dependency parentDependency : dependencyParents)
{
ClassTarget dependencyParent = (ClassTarget) parentDependency.getTo();
dependencyError = checkDependecyCompilationError(dependencyParent);
if (dependencyError)
{
break outerloop;
}
}
}
}
return dependencyError;
}
}
. - Package
. isSuspension
. Package
. Package
. init
. isUnnamedPackage
. getProject
. getBPackage
. getId
. getQualifiedName
. getRelativePath
. getPath
. getParent
. getChildren
. setStatus
. setEditor
. getEditor
. setUI
. getUI
. addListener
. removeListener
. getLastSavedProperties
. getSelectedTargets
. findTargets
. load
. refreshPackage
. getPkgFile
. positionNewTarget
. addImmovableTargets
. reload
. reReadGraphLayout
. repaint
. save
. addPackage
. getDebugger
. loadClass
. getVertices
. getTestTargets
. compile
. compile
. compilerMessage
. startCompile
. endCompile
. compile
. compile
. compileQuiet
. searchCompile
. doCompile
. isDebuggerIdle
. checkCompile
. compileOnceIdle
. processDebuggerEvent
. generateDocumentation
. reInitBreakpoints
. removeStepMarks
. addTarget
. removeTarget
. updateTargetIdentifier
. removeArrow
. userRemoveDependency
. if
. recalcArrows
. getClassTargets
. getAllClassnames
. getAllClassnamesWithSource
. isPackage
. isPackageFileName
. targetSelected
. showError
. showMessage
. showMessageWithText
. forgetLastSource
. showSource
. showSource
. calculateMessage
. showEditorMessage
. editorForTarget
. getTargetForSource
. showEditorDiagnostic
. hitBreakpoint
. showSourcePosition
. exceptionMessage
. getResourcePath
. checkClassMatchesFile
top,
use,
map,
class QuietPackageCompileObserver
. QuietPackageCompileObserver
. markAsCompiling
. sendEventToExtensions
. startCompile
. compilerMessage
. errorMessage
. warningMessage
. endCompile
top,
use,
map,
class MisspeltMethodChecker
. MisspeltMethodChecker
. chopAtOpeningBracket
. getLine
. getLineStart
. calculateMessage
. convertColumn
top,
use,
map,
class PackageCompileObserver
. PackageCompileObserver
. startCompile
. compilerMessage
. errorMessage
. closeAllEditors
. getCallHistory
. toString
. getDefaultSourceType
. addDependency
. addDependency
. removeDependency
. callStaticMethodOrConstructor
. addCompileObserver
. checkDependecyCompilationError
2939 neLoCode
+ 478 LoComm