package bluej.pkgmgr.target;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import bluej.pkgmgr.*;
import bluej.pkgmgr.Package;
import bluej.pkgmgr.dependency.*;
import bluej.utility.javafx.FXPlatformConsumer;
import javafx.geometry.Point2D;
import threadchecker.OnThread;
import threadchecker.Tag;
| A target that has relationships to other targets
|
| @author Michael Cahill
| @author Michael Kolling
|
public abstract class DependentTarget
extends EditableTarget{
| States. A compile target has two pieces of information.
| It can be up-to-date (i.e. class file matches latest source state)
| or it can need a compile (i.e. class file lags source state) with unknown error state,
| or it can need a compile and be known to have an error.
|
@OnThread(Tag.Any)
public static enum State
{
COMPILED, NEEDS_COMPILE, HAS_ERROR;
}
@OnThread(Tag.Any)
private final AtomicReference<State> state = new AtomicReference<>(State.NEEDS_COMPILE);
@OnThread(Tag.FXPlatform)
protected final List<TargetListener> stateListeners = new ArrayList<>();
@OnThread(value = Tag.Any, requireSynchronized = true)
private List<UsesDependency> inUses;
@OnThread(value = Tag.Any, requireSynchronized = true)
private List<UsesDependency> outUses;
@OnThread(value = Tag.Any, requireSynchronized = true)
private List<Dependency> parents;
@OnThread(value = Tag.Any, requireSynchronized = true)
private List<Dependency> children;
@OnThread(value = Tag.Any,requireSynchronized = true)
protected DependentTarget assoc;
| Create a new target belonging to the specified package.
|
public DependentTarget(Package pkg, String identifierName)
{
super(pkg, identifierName);
inUses = new ArrayList<>();
outUses = new ArrayList<>();
parents = new ArrayList<>();
children = new ArrayList<>();
assoc = null;
}
@Override
@OnThread(Tag.FXPlatform)
public void setPos(int x, int y)
{
super.setPos(x,y);
recalcDependentPositions();
}
@Override
@OnThread(Tag.FXPlatform)
public void setSize(int width, int height)
{
super.setSize(width, height);
recalcDependentPositions();
}
| Save association information about this class target
| @param props the properties object to save to
| @param prefix an internal name used for this target to identify
|
@Override
@OnThread(Tag.FXPlatform)
public void save(Properties props, String prefix)
{
super.save(props, prefix);
if (getAssociation() != null) {
String assocName = getAssociation().getIdentifierName();
props.put(prefix + ".association", assocName);
}
}
@OnThread(Tag.FXPlatform)
public synchronized void setAssociation(DependentTarget t)
{
assoc = t;
if (assoc != null && assoc.isMoveable()){
assoc.setIsMoveable(false);
}
if (assoc != null && assoc.isResizable())
{
assoc.setResizable(false);
}
}
@OnThread(value = Tag.Any, requireSynchronized = true)
public synchronized DependentTarget getAssociation()
{
return assoc;
}
@OnThread(Tag.FXPlatform)
public synchronized void addDependencyOut(Dependency d, boolean recalc)
{
if (d instanceof UsesDependency) {
if (outUses.contains(d))
return;
outUses.add((UsesDependency) d);
if (recalc)
recalcOutUses();
}
else if ((d instanceof ExtendsDependency)
|| (d instanceof ImplementsDependency)) {
if (parents.contains(d))
return;
parents.add(d);
}
}
@OnThread(Tag.FXPlatform)
public synchronized void addDependencyIn(Dependency d, boolean recalc)
{
if (d instanceof UsesDependency) {
if (inUses.contains(d))
return;
inUses.add((UsesDependency) d);
if (recalc)
recalcInUses();
}
else if ((d instanceof ExtendsDependency)
|| (d instanceof ImplementsDependency)) {
if (children.contains(d))
return;
children.add(d);
}
}
@OnThread(Tag.FXPlatform)
public synchronized void removeDependencyOut(Dependency d, boolean recalc)
{
if (d instanceof UsesDependency) {
outUses.remove(d);
if (recalc)
recalcOutUses();
}
else if ((d instanceof ExtendsDependency)
|| (d instanceof ImplementsDependency)) {
parents.remove(d);
}
}
@OnThread(Tag.FXPlatform)
public synchronized void removeDependencyIn(Dependency d, boolean recalc)
{
if (d instanceof UsesDependency) {
inUses.remove(d);
if (recalc) {
recalcInUses();
}
}
else if ((d instanceof ExtendsDependency)
|| (d instanceof ImplementsDependency)) {
children.remove(d);
}
}
@OnThread(Tag.Any)
public synchronized Collection dependencies()
{
List<Dependency> d = new ArrayList<>();
d.addAll(parents);
d.addAll(outUses);
return d;
}
@OnThread(Tag.Any)
public synchronized Collection dependents()
{
List<Dependency> d = new ArrayList<>();
d.addAll(children);
d.addAll(inUses);
return d;
}
| Get the dependencies between this target and its parent(s).
| The returned list should not be modified and may be a view or a copy.
|
@OnThread(value = Tag.Any, requireSynchronized = true)
public synchronized List getParents()
{
return Collections.unmodifiableList(new ArrayList<>(parents));
}
| Get the dependencies between this target and its children.
|
| @return
|
@OnThread(value = Tag.Any)
public synchronized List getChildrenDependencies()
{
return Collections.unmodifiableList(new ArrayList<>(children));
}
@OnThread(Tag.Any)
public synchronized List dependentsAsList()
{
List<Dependency> list = new LinkedList<Dependency>();
list.addAll(inUses);
list.addAll(outUses);
list.addAll(children);
list.addAll(parents);
return list;
}
@OnThread(Tag.Any)
public synchronized List usesDependencies()
{
return Collections.unmodifiableList(new ArrayList<>(outUses));
}
| Remove all outgoing dependencies. Also updates the package. (Don't
| call from package remove method - this will cause infinite recursion.)
|
@OnThread(Tag.FXPlatform)
protected synchronized void removeAllOutDependencies()
{
if (!outUses.isEmpty()) {
Dependency[] outUsesArray = new Dependency[outUses.size()];
outUses.toArray(outUsesArray);
for (int i = 0; i < outUsesArray.length ; i++) {
getPackage().removeDependency(outUsesArray[i], false);
}
}
removeInheritDependencies();
}
| Remove inheritance dependencies.
|
@OnThread(Tag.FXPlatform)
protected synchronized void removeInheritDependencies()
{
if (!parents.isEmpty()) {
Dependency[] parentsArray = new Dependency[ parents.size() ];
parents.toArray(parentsArray);
for (int i = 0; i < parentsArray.length ; i++)
getPackage().removeDependency(parentsArray[i], false);
}
}
| Remove all incoming dependencies. Also updates the package. (Don't
| call from package remove method - this will cause infinite recursion.)
|
@OnThread(Tag.FXPlatform)
protected synchronized void removeAllInDependencies()
{
if (!inUses.isEmpty()) {
Dependency[] inUsesArray = new Dependency[ inUses.size() ];
inUses.toArray(inUsesArray);
for (int i = 0; i < inUsesArray.length ; i++)
getPackage().removeDependency(inUsesArray[i], false);
}
if (!children.isEmpty()) {
Dependency[] childrenArray = new Dependency[ children.size() ];
children.toArray(childrenArray);
for (int i = 0; i < childrenArray.length ; i++)
getPackage().removeDependency(childrenArray[i], false);
}
}
@OnThread(Tag.FXPlatform)
public void recalcOutUses()
{
List<UsesDependency> visibleOutUses = getVisibleUsesDependencies(usesDependencies());
Collections.sort(visibleOutUses, new LayoutComparer(this, false));
int cy = getY() + (int)getHeight() / 2;
int n_top = 0, n_bottom = 0;
for (int i = visibleOutUses.size() - 1; i >= 0; i--) {
Target to = ((Dependency) visibleOutUses.get(i)).getTo();
int to_cy = to.getY() + (int)to.getHeight() / 2;
if (to_cy < cy)
++n_top;
else{ ++n_bottom;
}
}
int top_left = getX() + ((int)getWidth() - (n_top - 1) * ARR_HORIZ_DIST) / 2;
int bottom_left = getX() + ((int)getWidth() - (n_bottom - 1) * ARR_HORIZ_DIST) / 2;
for (int i = 0; i < n_top + n_bottom; i++) {
UsesDependency d = (UsesDependency) visibleOutUses.get(i);
int to_cy = d.getTo().getY() + (int)d.getTo().getHeight() / 2;
if (to_cy < cy) {
d.setSourceCoords(top_left, getY() - 2.5, true);
top_left += ARR_HORIZ_DIST;
}
else {
d.setSourceCoords(bottom_left, getY() + getHeight() + 2.5, false);
bottom_left += ARR_HORIZ_DIST;
}
}
}
| Re-layout arrows into this target
|
@OnThread(Tag.FXPlatform)
public synchronized void recalcInUses()
{
List<UsesDependency> visibleInUses = getVisibleUsesDependencies(inUses);
Collections.sort(visibleInUses, new LayoutComparer(this, true));
int cx = getX() + (int)getWidth() / 2;
int n_left = 0, n_right = 0;
for (int i = visibleInUses.size() - 1; i >= 0; i--)
{
Target from = ((Dependency) visibleInUses.get(i)).getFrom();
int from_cx = from.getX() + (int)from.getWidth() / 2;
if (from_cx < cx)
++n_left;
else{ ++n_right;
}
}
int left_top = getY() + ((int)getHeight() - (n_left - 1) * ARR_VERT_DIST) / 2;
int right_top = getY() + ((int)getHeight() - (n_right - 1) * ARR_VERT_DIST) / 2;
for (int i = 0; i < n_left + n_right; i++)
{
UsesDependency d = (UsesDependency) visibleInUses.get(i);
int from_cx = d.getFrom().getX() + (int)d.getFrom().getWidth() / 2;
if (from_cx < cx)
{
d.setDestCoords(getX() - 4, left_top, true);
left_top += ARR_VERT_DIST;
}
else
{
d.setDestCoords(getX() + (int)getWidth() + 4, right_top, false);
right_top += ARR_VERT_DIST;
}
}
}
| Returns from the specified {}link List} all uses dependencies which are
| currently visible.
|
| @param usesDependencies
| A {}link List} of uses dependencies.
| @return A {}link List} containing all visible uses dependencies from the
| input list.
|
@OnThread(Tag.FXPlatform)
private static List getVisibleUsesDependencies(List<UsesDependency> usesDependencies)
{
List<UsesDependency> result = new ArrayList<UsesDependency>();
for (UsesDependency incomingUsesDependency : usesDependencies) {
if (incomingUsesDependency.isVisible()) {
result.add(incomingUsesDependency);
}
}
return result;
}
@OnThread(Tag.FXPlatform)
public Point2D getAttachment(double angle)
{
double radius;
double sin = Math.sin(angle);
double cos = Math.cos(angle);
double tan = sin / cos;
double m = (double) getHeight() / getWidth();
if (Math.abs(tan) < m)
radius = 0.5 * getWidth() / Math.abs(cos);
else{
radius = 0.5 * getHeight() / Math.abs(sin);
}
javafx.geometry.Point2D p = new Point2D(getX() + getWidth() / 2 + (int)(radius * cos),
getY() + getHeight() / 2 - (int)(radius * sin));
|
|
|if((-m < tan) && (tan < m) && (cos > 0)) // right side
|
|p.x += SHAD_SIZE;
|
|if((Math.abs(tan) > m) && (sin < 0) && (p.x > getX() + SHAD_SIZE)) // bottom
|
|p.y += SHAD_SIZE;
return p;
}
| The user may have moved or resized the target. If so, recalculate the
| dependency arrows associated with this target.
| @param editor
|
@OnThread(Tag.FXPlatform)
public synchronized void recalcDependentPositions()
{
recalcInUses();
recalcOutUses();
for (Iterator<UsesDependency> it = inUses.iterator(); it.hasNext(); ) {
Dependency d = it.next();
d.getFrom().recalcOutUses();
}
for (Iterator<UsesDependency> it = outUses.iterator(); it.hasNext(); ) {
Dependency d = it.next();
d.getTo().recalcInUses();
}
updateAssociatePosition();
}
@OnThread(Tag.FXPlatform)
protected void updateAssociatePosition()
{
DependentTarget t = getAssociation();
if (t != null) {
t.setPos(getX() + 30, getY() - 30);
if (isResizable())
t.setSize(getWidth(), getHeight());
t.recalcDependentPositions();
}
}
@Override
public String toString()
{
return getDisplayName();
}
| Return the current state of the target (one of S_NORMAL, S_INVALID,
| S_COMPILING)
|
@OnThread(Tag.Any)
public State getState()
{
return state.get();
}
| Mark the class as needing a compile (if it is not marked thus already).
|
| Do not call this method on classes which lack source code.
|
public void markModified()
{
if (getState() == State.COMPILED)
setState(State.NEEDS_COMPILE);
}
| Change the state of this target. The target will be repainted to show the
| new state.
|
| @param newState The new state value
|
@OnThread(Tag.FXPlatform)
public void setState(State newState)
{
state.set(newState);
repaint();
redraw();
for (TargetListener stateListener : stateListeners)
{
stateListener.stateChanged(newState);
}
}
| Adds a TargetListener to changes in this target.
|
@OnThread(Tag.FXPlatform)
public void addListener(TargetListener listener)
{
stateListeners.add(listener);
}
| Removes a listener added by addListener
|
@OnThread(Tag.FXPlatform)
public void removeListener(TargetListener listener)
{
stateListeners.remove(listener);
}
| A listener to changes in a DependentTarget
|
public static interface TargetListener
{
| Called when the editor has been opened. If the same Editor instance is opened and closed
| multiple times, this method is called on every open.
|
public void editorOpened();
| Called when state has changed
|
public void stateChanged(State newState);
| Called when the target is renamed.
|
public void renamed(String newName);
}
}
top,
use,
map,
abstract class DependentTarget
. DependentTarget
. setPos
. setSize
. save
. setAssociation
. getAssociation
. addDependencyOut
. addDependencyIn
. removeDependencyOut
. removeDependencyIn
. dependencies
. dependents
. getParents
. getChildrenDependencies
. dependentsAsList
. usesDependencies
. removeAllOutDependencies
. removeInheritDependencies
. removeAllInDependencies
. recalcOutUses
. recalcInUses
. getVisibleUsesDependencies
. getAttachment
. recalcDependentPositions
. updateAssociatePosition
. toString
. getState
. markModified
. setState
. addListener
. removeListener
top,
use,
map,
interface TargetListener
. editorOpened
. stateChanged
. renamed
619 neLoCode
+ 49 LoComm