package greenfoot.guifx.classes;

import bluej.Config;
import bluej.debugger.gentype.Reflective;
import bluej.editor.Editor;
import bluej.extensions.SourceType;
import bluej.pkgmgr.Package;
import bluej.pkgmgr.target.ClassTarget;
import bluej.pkgmgr.target.DependentTarget.State;
import bluej.pkgmgr.target.DependentTarget.TargetListener;
import bluej.utility.javafx.JavaFXUtil;
import greenfoot.guifx.GreenfootStage;
import greenfoot.guifx.classes.GClassDiagram.GClassType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.image.Image;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import threadchecker.OnThread;
import threadchecker.Tag;

import java.io.File;
import java.lang.reflect.Modifier;
import java.util.List;


| A version of GClassNode that handles extra actions and updates for local classes | (i.e. classes that are in this project, rather than Actor and World | which are imported). | public class LocalGClassNode extends GClassNode implements TargetListener{ private final GClassType type; private GClassDiagram classDiagram; private final ClassTarget classTarget; private String imageFilename;
| Make an instance for the given ClassTarget. The image will be retrieved from the project | properties. | | @param classTarget The ClassTarget to make an instance for | @param subClasses The sub-classes of this GClassNode | @param type The type of this class (Actor/World child, or Other) | public LocalGClassNode(GClassDiagram classDiagram, ClassTarget classTarget, List<GClassNode> subClasses, GClassType type) { super(getImageForClass(classTarget, type), subClasses, classDiagram.getSelectionManager()); this.imageFilename = classTarget.getPackage().getLastSavedProperties() .getProperty("class." + classTarget.getQualifiedName() + ".image"); this.classDiagram = classDiagram; this.classTarget = classTarget; this.type = type; setImageForEditor(); } @Override public String getQualifiedName() { return classTarget.getQualifiedName(); } @Override public String getDisplayName() { return classTarget.getBaseName(); }
| Get the image for a class, if any. A class "inherits" its super-class image if it does not |* have a specific image set. May return null. * @param classTarget The ClassTarget to get image for. * @param type The source type of this class node. * @return The image for the class or null if it has no image. private static Image getImageForClass(ClassTarget classTarget, GClassType type) { if (type == GClassType.OTHER) { return null; } return JavaFXUtil.loadImage(getImageFilename(classTarget)); }
| Returns a file name for the image of the first class in the given class' class hierarchy | that has an image set. | private static File getImageFilename(ClassTarget ct) { String className = ct.getQualifiedName(); Reflective type = ct.getTypeReflective(); Package pkg = ct.getPackage(); do { String imageFileName = pkg.getLastSavedProperties() .getProperty("class." + className + ".image"); if (imageFileName != null) { File imageDir = new File(pkg.getProject().getProjectDir(), "images"); return new File(imageDir, imageFileName); } if (type != null) { type = type.getSuperTypesR().stream().filter(t -> !t.isInterface()).findFirst().orElse(null); className = (type != null) ? type.getName() : null; } } while (type != null){; return null; } }
| Setup the given ClassDisplay with custom actions | @Override protected void setupClassDisplay(GreenfootStage greenfootStage, ClassDisplay display) { display.setOnContextMenuRequested(e -> { e.consume(); showContextMenu(greenfootStage, display, e); }); display.setOnMouseClicked(e -> { if (e.getButton() == MouseButton.PRIMARY && e.getClickCount() == 2) { classTarget.open(); } }); classTarget.addListener(this); stateChanged(classTarget.getState()); } @Override public void editorOpened() { setImageForEditor(); }
| Set the header image for the editor, if it has been opened. | private void setImageForEditor() { Editor editor = classTarget.getEditorIfOpen(); if (editor != null) { editor.setHeaderImage(image); } } @Override protected void setImage(Image newImage) { super.setImage(newImage); setImageForEditor(); } @Override public void stateChanged(State newState) { Paint fill; switch (newState) { case NEEDS_COMPILE: fill = ClassTarget.getGreyStripeFill(); break; case HAS_ERROR: fill = ClassTarget.getRedStripeFill(); break; default: fill = Color.TRANSPARENT; } display.setStripePattern(fill); if (newState != State.COMPILED) { classDiagram.getGreenfootStage().classModified(); } } @Override public void renamed(String newName) { classDiagram.getGreenfootStage().saveAndMirrorClassImageFilename(newName, getImageFilename()); classDiagram.recalculateGroups(); } @Override public void tidyup() { super.tidyup(); classTarget.removeListener(this); }
| Shows a context menu. | @param greenfootStage The GreenfootStage, needed for some actions | @param display The ClassDisplay we are showing the menu on. | @param e The event that triggered the showing. | @OnThread(Tag.FXPlatform) private void showContextMenu(GreenfootStage greenfootStage, ClassDisplay display, ContextMenuEvent e) { if (curContextMenu != null) { curContextMenu.hide(); curContextMenu = null; classDiagram.hideContextMenu(); } ContextMenu contextMenu = new ContextMenu(); Class<?> cl = null; if (classTarget.isCompiled()) { cl = classTarget.getPackage().loadClass(classTarget.getQualifiedName()); } contextMenu.getScene().setOnMouseMoved(ev -> greenfootStage.setLatestMousePosOnScreen(ev.getScreenX(), ev.getScreenY())); if (cl != null) { if (classTarget.getRole().createClassConstructorMenu(contextMenu.getItems(), classTarget, cl)) { contextMenu.getItems().add(new SeparatorMenuItem()); } if (classTarget.getRole().createClassStaticMenu(contextMenu.getItems(), classTarget, cl)) { contextMenu.getItems().add(new SeparatorMenuItem()); } } else { MenuItem menuItem = new MenuItem(Config.getString("classPopup.needsCompile")); menuItem.setDisable(true); contextMenu.getItems().add(menuItem); contextMenu.getItems().add(new SeparatorMenuItem()); } if (classTarget.hasSourceCode() || classTarget.getDocumentationFile().exists()) { contextMenu.getItems().add(GClassDiagram.contextInbuilt( Config.getString(classTarget.hasSourceCode() ? "edit.class" : "show.apidoc"), classTarget::open)); } if (type == GClassType.ACTOR || type == GClassType.WORLD) { contextMenu.getItems().add(GClassDiagram.contextInbuilt(Config.getString("select.image"), () -> greenfootStage.setImageFor(this))); } contextMenu.getItems().add(classTarget.new InspectAction(cl != null, display)); contextMenu.getItems().add(new SeparatorMenuItem()); if (classTarget.hasSourceCode()) { contextMenu.getItems().add(GClassDiagram.contextInbuilt(Config.getString("duplicate.class"), () -> greenfootStage.duplicateClass(this, classTarget))); } contextMenu.getItems().add(GClassDiagram.contextInbuilt(Config.getString("remove.class"), () -> { classTarget.remove(); classDiagram.recalculateGroups(); greenfootStage.fireWorldRemovedCheck(classTarget); })); if (classTarget.getSourceType() == SourceType.Stride) { contextMenu.getItems().add(classTarget.new ConvertToJavaAction(greenfootStage)); } else if (classTarget.getSourceType() == SourceType.Java && classTarget.getRole() != null && classTarget.getRole().canConvertToStride()) { contextMenu.getItems().add(classTarget.new ConvertToStrideAction(greenfootStage)); } boolean isFinal = false; if (cl != null) { isFinal = Modifier.isFinal(cl.getModifiers()); } else { Reflective ctReflective = classTarget.getTypeReflective(); if (ctReflective != null) { isFinal = ctReflective.isFinal(); } } if (! isFinal) { contextMenu.getItems().add(GClassDiagram.contextInbuilt(Config.getString("new.sub.class"), () -> greenfootStage.newSubClassOf(classTarget.getQualifiedName(), type))); } classDiagram.getSelectionManager().select(display); contextMenu.show(display, e.getScreenX(), e.getScreenY()); curContextMenu = contextMenu; } @Override public String getImageFilename() { return imageFilename; }
| Set the image filename for this class node. The displayed image will be changed to match. | public void setImageFilename(String newImageFilename) { this.imageFilename = newImageFilename; if (newImageFilename != null) { File imageDir = new File(classTarget.getPackage().getProject().getProjectDir(), "images"); File imageFile = new File(imageDir, imageFilename); setImage(JavaFXUtil.loadImage(imageFile)); } else { setImage(null); } }
| Get the class target of this class | public ClassTarget getClassTarget() { return classTarget; } }
top, use, map, class LocalGClassNode

.   LocalGClassNode
.   getQualifiedName
.   getDisplayName
.   getImageForClass
.   getImageFilename
.   setupClassDisplay
.   editorOpened
.   setImageForEditor
.   setImage
.   stateChanged
.   renamed
.   tidyup
.   showContextMenu
.   getImageFilename
.   setImageFilename
.   getClassTarget




426 neLoCode + 19 LoComm