//----------------------------------------------------------------------------// // // // P l u g i n s M a n a g e r // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr.plugin; import omr.WellKnowns; import omr.constant.Constant; import omr.constant.ConstantSet; import omr.score.Score; import omr.score.ui.ScoreController; import omr.score.ui.ScoreDependent; import omr.sheet.ui.SheetsController; import omr.ui.util.SeparableMenu; import omr.util.FileUtil; import omr.util.Param; import org.jdesktop.application.Action; import org.jdesktop.application.Task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.event.ActionEvent; import java.io.File; import java.io.FileFilter; import java.util.Collection; import java.util.Map; import java.util.TreeMap; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import omr.step.PluginStep; import omr.step.Steps; /** * Class {@code PluginsManager} handles the collection of application * registered plugins. * Each registered plugin is represented by a menu item. * One of these plugins can be set as the default editor plugin and directly * launched by the dedicated toolbar button. * * <p>Any file, with the ".js" extension, found in the * <code>plugins</code> * folder will lead to the creation of a corresponding Plugin instance.</p> * * @author Hervé Bitteur */ public class PluginsManager extends ScoreDependent { //~ Static fields/initializers --------------------------------------------- /** Specific application parameters */ private static final Constants constants = new Constants(); /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger(PluginsManager.class); /** Singleton. */ private static PluginsManager INSTANCE; /** Filter for plugin script files. */ private static final FileFilter pluginFilter = new FileFilter() { @Override public boolean accept (File pathname) { // Check for proper extension String ext = FileUtil.getExtension(pathname); if (ext.equalsIgnoreCase(".js")) { return true; } else { return false; } } }; /** Default plugin id. */ public static final Param<String> defaultPluginId = new Default(); //~ Instance fields -------------------------------------------------------- // /** The concrete UI menu. */ private JMenu menu; /** The sorted collection of registered plugins: ID -> Plugin. */ private final Map<String, Plugin> map = new TreeMap<>(); /** The default plugin. */ private Plugin defaultPlugin; //~ Constructors ----------------------------------------------------------- // //----------------// // PluginsManager // //----------------// /** * Generates the menu to be inserted in the plugin menu hierarchy, * based on the script files discovered in the plugin folder. * * @param menu the hosting menu, or null */ private PluginsManager () { // Browse the plugin folder for relevant scripts File pluginDir = WellKnowns.PLUGINS_FOLDER; if (pluginDir.exists() && pluginDir.isDirectory()) { for (File file : pluginDir.listFiles(pluginFilter)) { try { Plugin plugin = new Plugin(file); map.put(plugin.getId(), plugin); } catch (Exception ex) { logger.warn("Could not process plugin file {} [{}]", file, ex); } } // Default plugin, if any is defined setDefaultPlugin(constants.defaultPlugin.getValue().trim()); } } //~ Methods ---------------------------------------------------------------- //------------// // getPlugins // //------------// /** * Report the collection of plugins ids * * @return the various plugins ids */ public Collection<String> getPluginIds () { return map.keySet(); } //------------------// // getDefaultPlugin // //------------------// /** * Return the default plugin if any. * * @return the default plugin, or null if none is defined */ public Plugin getDefaultPlugin () { return defaultPlugin; } //------------------// // setDefaultPlugin // //------------------// /** * Assign the default plugin. */ public final void setDefaultPlugin (String pluginId) { Plugin plugin = findDefaultPlugin(pluginId); if (!pluginId.isEmpty() && (plugin == null)) { logger.warn("Could not find default plugin {}", pluginId); } else { setDefaultPlugin(plugin); } } //------------------// // setDefaultPlugin // //------------------// /** * Assign the default plugin. */ public final void setDefaultPlugin (Plugin defaultPlugin) { Plugin oldDefaultPlugin = this.defaultPlugin; this.defaultPlugin = defaultPlugin; if (oldDefaultPlugin != null) { PluginStep pluginStep = (PluginStep) Steps.valueOf(Steps.PLUGIN); pluginStep.setPlugin(defaultPlugin); } } //-------------// // getInstance // //-------------// /** * Report the class singleton. * * @return the unique instance of this class */ public static synchronized PluginsManager getInstance () { if (INSTANCE == null) { INSTANCE = new PluginsManager(); } return INSTANCE; } //---------// // getMenu // //---------// /** * Report the concrete UI menu of all plugins * * @param menu a preallocated menu instance, or null * @return the populated menu entity */ public JMenu getMenu (JMenu menu) { if (menu == null) { menu = new SeparableMenu(); } for (Plugin plugin : map.values()) { menu.add(new JMenuItem(new PluginAction(plugin))); } // Listener to modify attributes on-the-fly menu.addMenuListener(new MyMenuListener()); this.menu = menu; return menu; } //--------------// // invokeEditor // //--------------// /** * Action to invoke the default score editor * * @param e the event that triggered this action */ @Action(enabledProperty = SCORE_AVAILABLE) public Task<Void, Void> invokeDefaultPlugin (ActionEvent e) { if (defaultPlugin == null) { logger.warn("No default plugin defined"); return null; } // Current score export file final Score score = ScoreController.getCurrentScore(); if (score == null) { return null; } else { return defaultPlugin.getTask(score); } } //-------------------// // findDefaultPlugin // //-------------------// private Plugin findDefaultPlugin (String pluginId) { for (Plugin plugin : map.values()) { if (plugin.getId().equalsIgnoreCase(pluginId)) { return plugin; } } return null; } //~ Inner Classes ---------------------------------------------------------- //-----------// // Constants // //-----------// private static final class Constants extends ConstantSet { //~ Instance fields ---------------------------------------------------- Constant.String defaultPlugin = new Constant.String( "", "Name of default plugin"); } //----------------// // MyMenuListener // //----------------// /** * Class {@code MyMenuListener} is triggered when menu is entered. * This is meant to enable menu items only when a sheet is selected. */ private class MyMenuListener implements MenuListener { //~ Methods ------------------------------------------------------------ @Override public void menuCanceled (MenuEvent e) { } @Override public void menuDeselected (MenuEvent e) { } @Override public void menuSelected (MenuEvent e) { boolean enabled = SheetsController.getCurrentSheet() != null; for (int i = 0; i < menu.getItemCount(); i++) { JMenuItem menuItem = menu.getItem(i); // Beware of separators (for which returned menuItem is null) if (menuItem != null) { menuItem.setEnabled(enabled); } } } } //---------// // Default // //---------// private static class Default extends Param<String> { @Override public String getSpecific () { return constants.defaultPlugin.getValue(); } @Override public boolean setSpecific (String specific) { if (!getSpecific().equals(specific)) { constants.defaultPlugin.setValue(specific); getInstance().setDefaultPlugin(specific); logger.info("Default plugin is now ''{}''", specific); return true; } return false; } } }