subfolders = new HashMap<>();
for (Library library : contribLibraries) {
JMenuItem item = new JMenuItem(library.getName());
item.addActionListener(listener);
// changed to library-name to facilitate specification if imports from properties file
item.setActionCommand(library.getName());
String group = library.getGroup();
if (group != null) {
JMenu subMenu = subfolders.get(group);
if (subMenu == null) {
subMenu = new JMenu(group);
importMenu.add(subMenu);
subfolders.put(group, subMenu);
}
subMenu.add(item);
} else {
importMenu.add(item);
}
}
}
}
/**
* Require examples to explicitly state that they're compatible with this
* Mode before they're included. Helpful for Modes like p5js or Python
* where the .java examples cannot be used.
* @since 3.2
* @return true if an examples package must list this Mode's identifier
*/
public boolean requireExampleCompatibility() {
return false;
}
/**
* Override this to control the order of the first set of example folders
* and how they appear in the examples window.
*/
public File[] getExampleCategoryFolders() {
return examplesFolder.listFiles((dir, name) -> dir.isDirectory() && name.charAt(0) != '.');
}
public void rebuildExamplesFrame() {
if (examplesFrame != null) {
boolean visible = examplesFrame.isVisible();
Rectangle bounds = null;
if (visible) {
bounds = examplesFrame.getBounds();
examplesFrame.setVisible(false);
examplesFrame.dispose();
}
examplesFrame = null;
if (visible) {
showExamplesFrame();
examplesFrame.setBounds(bounds);
}
}
}
public void showExamplesFrame() {
if (examplesFrame == null) {
examplesFrame = new ExamplesFrame(base, this);
}
examplesFrame.setVisible();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Get an ImageIcon object from the Mode folder.
* Or when prefixed with /lib, load it from the main /lib folder.
* @since 3.0a6
*/
public ImageIcon loadIcon(String filename) {
if (filename.startsWith("/lib/")) {
return Toolkit.getLibIcon(filename.substring(5));
}
File file = new File(folder, filename);
if (!file.exists()) {
return null;
}
return new ImageIcon(file.getAbsolutePath());
}
/**
* Get an image object from the mode folder.
* Or when prefixed with /lib, load it from the main /lib folder.
*/
public Image loadImage(String filename) {
ImageIcon icon = loadIcon(filename);
if (icon != null) {
return icon.getImage();
}
return null;
}
public Image loadImageX(String filename) {
return loadImage(filename + "-" + Toolkit.highResMultiplier() + "x.png");
}
public String loadString(String filename) {
File file;
if (filename.startsWith("/lib/")) {
// remove the slash from the front
file = Platform.getContentFile(filename.substring(1));
} else {
file = new File(folder, filename);
}
return Util.loadFile(file);
}
/**
* Returns the HTML filename (including path prefix if necessary)
* for this keyword, or null if it doesn't exist.
*/
public String lookupReference(String keyword) {
return keywordToReference.get(keyword);
}
/**
* Specialized version of getTokenMarker() that can be overridden to
* provide different TokenMarker objects for different file types.
* @since 3.2
* @param code the code for which we need a TokenMarker
*/
@SuppressWarnings("unused")
public TokenMarker getTokenMarker(SketchCode code) {
return getTokenMarker();
}
public TokenMarker getTokenMarker() {
return tokenMarker;
}
protected TokenMarker createTokenMarker() {
return new PdeTokenMarker();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Breaking out extension types in order to clean up the code, and make it
// easier for other environments (like Arduino) to incorporate changes.
/**
* True if the specified extension should be hidden when shown on a tab.
* For Processing, this is true for .pde files. (Broken out for subclasses.)
* You can override this in your Mode subclass to handle it differently.
*/
public boolean hideExtension(String ext) {
return ext.equals(getDefaultExtension());
}
/**
* True if the specified code has the default file extension.
*/
public boolean isDefaultExtension(SketchCode code) {
return code.getExtension().equals(getDefaultExtension());
}
/**
* True if the specified extension is the default file extension.
*/
public boolean isDefaultExtension(String ext) {
return ext.equals(getDefaultExtension());
}
/**
* True if this Mode can edit this file (usually meaning that
* its extension matches one that is supported by the Mode).
*/
public boolean canEdit(final File file) {
final int dot = file.getName().lastIndexOf('.');
if (dot < 0) {
return false;
}
return validExtension(file.getName().substring(dot + 1));
}
public boolean canEdit(Sketch sketch) {
for (final SketchCode code : sketch.getCode()) {
if (!validExtension(code.getExtension())) {
return false;
}
}
return true;
}
/**
* Check this extension (no dots, please) against the list of valid
* extensions.
*/
public boolean validExtension(String what) {
String[] ext = getExtensions();
for (String s : ext) {
if (s.equals(what)) return true;
}
return false;
}
/**
* Returns the default extension for this editor setup.
*/
abstract public String getDefaultExtension();
/**
* Returns the appropriate file extension to use for auxiliary source
* files in a sketch. For example, in a Java-mode sketch, auxiliary files
* can be named "Foo.java"; in Python mode, they should be named "foo.py".
*
* Modes that do not override this function will get the
* default behavior of returning the default extension.
*/
public String getModuleExtension() {
return getDefaultExtension();
}
/**
* Returns a String[] array of proper extensions.
*/
abstract public String[] getExtensions();
/**
* Get array of file/directory names that needn't be copied during "Save As".
*/
abstract public String[] getIgnorable();
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Checks coreLibraries and contribLibraries for a library with the specified name
* @param libName the name of the library to find
* @return the Library or null if not found
*/
public Library findLibraryByName(String libName) {
for (Library lib : this.coreLibraries) {
if (libName.equals(lib.getName()))
return lib;
}
for (Library lib : this.contribLibraries) {
if (libName.equals(lib.getName()))
return lib;
}
return null;
}
/**
* Create a fresh application folder if the 'delete target folder'
* pref has been set in the preferences.
*/
public void prepareExportFolder(File targetFolder) {
if (targetFolder != null) {
// Nuke the old application folder because it can cause trouble
if (Preferences.getBoolean("export.delete_target_folder")) {
if (targetFolder.exists()) {
try {
Platform.deleteFile(targetFolder);
} catch (IOException e) {
// ignore errors/continue; likely to be ok
e.printStackTrace();
}
}
}
// Create a fresh output folder (needed before preproc is run next)
if (!targetFolder.exists()) {
if (!targetFolder.mkdirs()) {
Messages.err("Could not create " + targetFolder);
}
}
}
}
@Override
public String toString() {
return getTitle();
}
}