package bluej.extmgr;
import java.awt.Graphics2D;
import java.io.File;
import java.util.*;
import java.util.List;
import bluej.*;
import bluej.debugmgr.ExecutionEvent;
import bluej.extensions.BClassTarget;
import bluej.extensions.event.*;
import bluej.extensions.painter.ExtensionClassTargetPainter;
import bluej.pkgmgr.*;
import bluej.pkgmgr.Package;
import bluej.pkgmgr.Layer;
import bluej.utility.Debug;
import bluej.utility.javafx.FXPlatformSupplier;
import javax.swing.*;
import javafx.application.Platform;
import javafx.stage.Window;
import threadchecker.OnThread;
import threadchecker.Tag;
| Manages extensions and provides the main interface to them. A
| singleton.
|
| @author Clive Miller, University of Kent at Canterbury, 2002
| @author Damiano Bolla, University of Kent at Canterbury, 2003
| @author Michael Kolling
|
public class ExtensionsManager
implements BlueJEventListener{
private static ExtensionsManager instance;
| Singleton factory method.
|
public static synchronized ExtensionsManager getInstance()
{
if (instance == null) {
instance = new ExtensionsManager();
instance.loadExtensions();
}
return instance;
}
private List<ExtensionWrapper> extensions;
private ExtensionPrefManager prefManager = null;
| Constructor for the ExtensionsManager object. It is private, as the
| ExtensionsManager is a singleton.
|
private ExtensionsManager()
{
extensions = new ArrayList<ExtensionWrapper>();
BlueJEvent.addListener(this);
}
| Loads extensions that are in system and user location.
|
private void loadExtensions()
{
File systemDir = new File(Config.getBlueJLibDir(), "extensions");
String dirPath = Config.getPropString("bluej.extensions.systempath", null);
if (dirPath != null) {
systemDir = new File(dirPath);
}
loadDirectoryExtensions(systemDir, null);
loadDirectoryExtensions(Config.getUserConfigFile("extensions"), null);
}
| Unloads all extensions that are loaded. Normally called just before BlueJ
| is closing.
|
public void unloadExtensions()
{
synchronized(extensions) {
for (Iterator<ExtensionWrapper> iter = extensions.iterator(); iter.hasNext();) {
ExtensionWrapper aWrapper = iter.next();
aWrapper.terminate();
iter.remove();
}
}
}
| Searches through the given directory for jar files that contain a valid
| extension. On finding a loadable extension, try to load it.
|
| @param directory
| Where to look for extensions
| @param project
| A project this extension is bound to, or null if
| the extension is not bound to a specific project.
|
private void loadDirectoryExtensions(File directory, Project project)
{
File[] files = directory.listFiles();
if (files == null) {
return;
}
for (int index = 0; index < files.length; index++) {
File thisFile = files[index];
if (thisFile.isDirectory())
continue;
if (!thisFile.getName().endsWith(".jar"))
continue;
ExtensionWrapper aWrapper = new ExtensionWrapper(getPrefManager(), thisFile);
if (!aWrapper.isJarValid()) {
continue;
}
if (isWrapperAlreadyLoaded(aWrapper)) {
continue;
}
aWrapper.newExtension(project);
if (aWrapper.isValid()) {
synchronized (extensions) {
extensions.add(aWrapper);
}
}
}
getPrefManager().panelRevalidate();
}
| Checks if the loaded wrappers/extensions if is already loaded.
|
private boolean isWrapperAlreadyLoaded(ExtensionWrapper thisWrapper)
{
String thisClassName = thisWrapper.getExtensionClassName();
String thisJarName = thisWrapper.getExtensionFileName();
synchronized(extensions) {
for (ExtensionWrapper aWrapper : extensions) {
String aClassName = aWrapper.getExtensionClassName();
if (aClassName == null) {
continue;
}
if (thisClassName.equals(aClassName)) {
Debug.message("Extension is already loaded: " + thisClassName + " jarName=" + thisJarName);
return true;
}
}
}
return false;
}
| Return the preferences manager for extensions.
|
public ExtensionPrefManager getPrefManager()
{
if (prefManager == null) {
prefManager = new ExtensionPrefManager(extensions);
}
return prefManager;
}
| Ask for extension manager to show the help dialog for extensions. This is
| here to be sure that the help dialog is called when extension manager is
| valid.
|
public void showHelp(FXPlatformSupplier<Window> parentFrame)
{
List<ExtensionWrapper> extensionsList = new ArrayList<ExtensionWrapper>();
synchronized (extensions) {
extensionsList.addAll(extensions);
}
ExtensionsDialog dialog = new ExtensionsDialog(extensionsList, parentFrame);
Platform.runLater(dialog::showAndWait);
}
| Searches for and loads any new extensions found in the project.
|
public void projectOpening(Project project)
{
File exts = new File(project.getProjectDir(), "extensions");
loadDirectoryExtensions(exts, project);
}
| Inform extensions that a package has been opened
|
public void packageOpened(Package pkg)
{
delegateEvent(new PackageEvent(PackageEvent.PACKAGE_OPENED, pkg));
}
| This package frame is about to be closed. The issue here is to remove the
| extension if this is the right time to do it.
|
public void packageClosing(Package pkg)
{
delegateEvent(new PackageEvent(PackageEvent.PACKAGE_CLOSING, pkg));
boolean invalidateExtension = false;
Project thisProject = pkg.getProject();
if (thisProject == null) {
return;
}
PkgMgrFrame[] frameArray = PkgMgrFrame.getAllProjectFrames(thisProject);
if (frameArray == null) {
invalidateExtension = true;
}
else {
invalidateExtension = frameArray.length <= 1;
}
if (!invalidateExtension) {
return;
}
synchronized(extensions) {
for (Iterator<ExtensionWrapper> iter = extensions.iterator(); iter.hasNext();) {
ExtensionWrapper aWrapper = iter.next();
if (thisProject != aWrapper.getProject()) {
continue;
}
aWrapper.terminate();
iter.remove();
}
}
}
| Check whether the menus provided by this extension should not be shown for the
| given project.
|
| @param onThisProject the project to check whether menus should be shown (may be null)
| @param extensionProject the project which the extension was loaded for (may be null, for
| an extension not bound to a particular project)
|
private boolean skipThisMenu(Project onThisProject, Project extensionProject)
{
if (onThisProject == null && extensionProject == null)
return false;
if (onThisProject == null && extensionProject != null)
return true;
if (onThisProject != null && extensionProject == null)
return false;
if (onThisProject == extensionProject)
return false;
return true;
}
| Returns a List of menus currently provided by extensions.
|
LinkedList<JMenuItem> getMenuItems(ExtensionMenu attachedObject, Project onThisProject)
{
LinkedList<JMenuItem> menuItems = new LinkedList<JMenuItem>();
synchronized(extensions) {
for (ExtensionWrapper aWrapper : extensions) {
if (!aWrapper.isValid()) {
continue;
}
if (skipThisMenu(onThisProject, aWrapper.getProject())) {
continue;
}
JMenuItem anItem = aWrapper.safeGetMenuItem(attachedObject);
if (anItem == null) {
continue;
}
anItem.putClientProperty("bluej.extmgr.ExtensionWrapper", aWrapper);
menuItems.add(anItem);
}
}
return menuItems;
}
| Delegates an event to all known extensions.
|
public void delegateEvent(ExtensionEvent event)
{
synchronized(extensions) {
for (ExtensionWrapper wrapper : extensions) {
wrapper.safeEventOccurred(event);
}
}
}
| This is called back when some sort of event occurs. Depending on the
| event we will adapt it and send it up to the extension.
|
| @param eventId
| The event id (see BlueJEvent)
| @param arg
| This really depends on that event is given
| @param prj
| A project where the event happens
|
| @see BlueJEvent
|
@OnThread(Tag.SwingIsFX)
public void blueJEvent(int eventId, Object arg, Project prj)
{
if (eventId == BlueJEvent.EXECUTION_RESULT) {
ExecutionEvent exevent = (ExecutionEvent) arg;
delegateEvent(new InvocationEvent(exevent));
return;
}
}
| Calls the extension to draw its representation of a class target.
|
| @param layer
| The layer of the drawing which causes the different methods of
| the {}link ExtensionClassTargetPainter} instance to be called.
| @param bClassTarget
| The class target that will be painted.
| @param graphics
| The {}link Graphics2D} instance to draw on.
| @param width
| The width of the area to paint.
| @param height
| The height of the area to paint.
|
public void drawExtensionClassTarget(Layer layer, BClassTarget bClassTarget,
Graphics2D graphics, int width, int height)
{
synchronized (extensions) {
for (ExtensionWrapper extension : extensions) {
if (!extension.isValid()) {
continue;
}
extension.safeDrawExtensionClassTarget(layer, bClassTarget, graphics, width, height);
}
}
}
| Gets the loaded extensions, for data collection purposes.
|
| @param proj Pass a project to get the project-specific extensions,
| pass null to get *only* extensions that are not project-specific
|
public List getLoadedExtensions(Project proj)
{
ArrayList<ExtensionWrapper> r = new ArrayList<ExtensionWrapper>();
for (ExtensionWrapper ext : extensions)
{
if (ext.getProject() == proj)
{
r.add(ext);
}
}
return r;
}
}
top,
use,
map,
class ExtensionsManager
. getInstance
. ExtensionsManager
. loadExtensions
. unloadExtensions
. loadDirectoryExtensions
. isWrapperAlreadyLoaded
. getPrefManager
. showHelp
. projectOpening
. packageOpened
. packageClosing
. skipThisMenu
. delegateEvent
. blueJEvent
. drawExtensionClassTarget
. getLoadedExtensions
433 neLoCode
+ 58 LoComm