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