package org.goko.common.preferences.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.di.annotations.Creatable; import org.eclipse.e4.core.services.contributions.IContributionFactory; import org.eclipse.e4.core.services.log.Logger; import org.eclipse.jface.preference.IPreferenceNode; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceManager; import org.eclipse.jface.preference.PreferenceNode; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.goko.common.preferences.IPreferenceStoreProvider; import org.goko.common.preferences.ScopedPreferenceStore; import org.goko.core.config.GokoPreference; @Creatable public class E4PreferenceRegistry{ /* */ //public static final String PREFS_PAGE = "Goko.org.goko.ui.gkPreferencesPages"; public static final String PAGE_ID = "goko.org.ui.page.id"; /* */ public static final String PREFS_PAGE_XP = "Goko.org.goko.ui.gkPreferencePage"; // $NON-NLS-1$ public static final String PREF_STORE_PROVIDER = "Goko.org.goko.ui.gkPreferenceStoreProvider"; // $NON-NLS-1$ protected static final String ELMT_PAGE = "page"; // $NON-NLS-1$ protected static final String ATTR_ID = "id"; // $NON-NLS-1$ protected static final String ATTR_CATEGORY = "category"; // $NON-NLS-1$ protected static final String ATTR_CLASS = "class"; // $NON-NLS-1$ protected static final String ATTR_NAME = "name"; // $NON-NLS-1$ protected static final String ATTR_TARGET_BOARD = "targetBoard"; // $NON-NLS-1$ protected static final String ATTR_PLUGIN_ID = "pluginId"; // $NON-NLS-1$ protected static final String ATTR_ID_IN_WBCONTEXT = "idInWorkbenchContext"; // $NON-NLS-1$ @Inject protected Logger logger; @Inject protected IEclipseContext context; @Inject protected IExtensionRegistry registry; private PreferenceManager pm = null; // A map of (pluginId, { IPreferenceStoreProvider, or key in wbcontext } private Map<String, Object> psProviders; public PreferenceManager getPreferenceManager() { // Remember of the unbounded nodes to order parent pages. // Map<category, list of children> (all nodes except root nodes) Map<String, Collection<IPreferenceNode>> childrenNodes = new HashMap<String, Collection<IPreferenceNode>>(); if (pm != null) return pm; pm = new PreferenceManager(); IContributionFactory factory = context.get(IContributionFactory.class); String targetBoard = GokoPreference.getInstance().getTargetBoard(); for (IConfigurationElement elmt : registry.getConfigurationElementsFor(PREFS_PAGE_XP)) { String bundleId = elmt.getNamespaceIdentifier(); if (!elmt.getName().equals(ELMT_PAGE)) { logger.warn("unexpected element: {0}", elmt.getName()); continue; } else if (isEmpty(elmt.getAttribute(ATTR_ID)) || isEmpty(elmt.getAttribute(ATTR_NAME))) { logger.warn("missing id and/or name: {}", bundleId); continue; } String pageTargetBoard = elmt.getAttribute(ATTR_TARGET_BOARD); if(StringUtils.isNotBlank(pageTargetBoard) && !StringUtils.equals(pageTargetBoard, targetBoard)){ continue; // Page is not designed for target board. Ignore it } PreferenceNode pn = null; if (elmt.getAttribute(ATTR_CLASS) != null) { PreferencePage page = null; try { String prefPageURI = getClassURI(bundleId, elmt.getAttribute(ATTR_CLASS)); Object object = factory.create(prefPageURI, context); if (!(object instanceof PreferencePage)) { logger.error("Expected instance of PreferencePage: {0}", elmt.getAttribute(ATTR_CLASS)); continue; } page = (PreferencePage) object; setPreferenceStore(bundleId, page); } catch (ClassNotFoundException e) { logger.error(e); continue; } ContextInjectionFactory.inject(page, context); if ((page.getTitle() == null || page.getTitle().isEmpty()) && elmt.getAttribute(ATTR_NAME) != null) { page.setTitle(elmt.getAttribute(ATTR_NAME)); } pn = new PreferenceNode(elmt.getAttribute(ATTR_ID), page); } else { pn = new PreferenceNode(elmt.getAttribute(ATTR_ID), new EmptyPreferencePage(elmt.getAttribute(ATTR_NAME))); } // Issue 2 : Fix bug on order (see : // https://github.com/opcoach/e4Preferences/issues/2) // Add only pages at root level and remember of child pages for // categories String category = elmt.getAttribute(ATTR_CATEGORY); if (isEmpty(category)) { pm.addToRoot(pn); } else { /* * IPreferenceNode parent = findNode(pm, category); if (parent * == null) { // No parent found, but may be the extension has * not been read yet. So remember of it unboundedNodes.put(pn, * category); } else { parent.add(pn); } */ // Check if this category is already registered. Collection<IPreferenceNode> children = childrenNodes.get(category); if (children == null) { children = new ArrayList<IPreferenceNode>(); childrenNodes.put(category, children); } children.add(pn); } } // Must now bind pages that has not been added in nodes (depends on the // preference page read order) // Iterate on all possible categories Collection<String> categoriesDone = new ArrayList<String>(); while (!childrenNodes.isEmpty()) { for (String cat : Collections.unmodifiableSet(childrenNodes.keySet())) { // Is this category already in preference manager ? If not add // it later... IPreferenceNode parent = findNode(pm, cat); if (parent != null) { // Can add the list of children to this parent page... for (IPreferenceNode pn : childrenNodes.get(cat)) { parent.add(pn); } // Ok This parent page is done. Can remove it from map // outside of this loop categoriesDone.add(cat); } } for (String keyToRemove : categoriesDone) childrenNodes.remove(keyToRemove); categoriesDone.clear(); } return pm; } private void setPreferenceStore(String bundleId, PreferencePage page) { // Affect preference store to this page if this is a // PreferencePage, else, must manage it internally // Set the issue#1 on github : // https://github.com/opcoach/e4Preferences/issues/1 // And manage the extensions of IP initialisePreferenceStoreProviders(); IPreferenceStore store = null; // Get the preference store according to policy. Object data = psProviders.get(bundleId); if (data != null) { if (data instanceof IPreferenceStore) store = (IPreferenceStore) data; else if (data instanceof IPreferenceStoreProvider) store = ((IPreferenceStoreProvider) data).getPreferenceStore(); else if (data instanceof String) store = (IPreferenceStore) context.get((String) data); } else { // Default behavior : create a preference store for this bundle and remember of it store = new ScopedPreferenceStore(InstanceScope.INSTANCE, bundleId); psProviders.put(bundleId, store); } if (store != null) page.setPreferenceStore(store); else { logger.warn("Unable to set the preferenceStore for page " + page.getTitle() + " defined in bundle " + bundleId); } } /** Read the e4PreferenceStoreProvider extension point */ private void initialisePreferenceStoreProviders() { if (psProviders == null) { IContributionFactory factory = context.get(IContributionFactory.class); psProviders = new HashMap<String, Object>(); // Read extensions and fill the map... for (IConfigurationElement elmt : registry.getConfigurationElementsFor(PREF_STORE_PROVIDER)) { String declaringBundle = elmt.getNamespaceIdentifier(); //String pluginId = elmt.getAttribute(ATTR_PLUGIN_ID); // if (isEmpty(pluginId)) // { // logger.warn("missing plugin Id in extension " + PREF_STORE_PROVIDER + " check the plugin " + declaringBundle); // continue; // } if(psProviders.containsKey(declaringBundle)){ logger.error("Multiple preference store for a single bundle is not supported yet"); } String classname = elmt.getAttribute(ATTR_CLASS); String objectId = elmt.getAttribute(ATTR_ID_IN_WBCONTEXT); if ((isEmpty(classname) && isEmpty(objectId)) || (((classname != null) && classname.length() > 0) && ((objectId != null) && objectId.length() > 0))) { logger.warn("In extension " + PREF_STORE_PROVIDER + " only one of the two attributes (pluginId or idInWorkbenchContext) must be set. Check the plugin " + declaringBundle); continue; } // Ok can now work with data... Object data = objectId; if (classname != null) { try{ String classURI = getClassURI(declaringBundle, elmt.getAttribute(ATTR_CLASS)); data = factory.create(classURI, context); if (!(data instanceof IPreferenceStoreProvider)) { logger.warn("In extension " + PREF_STORE_PROVIDER + " the class must implements IPreferenceStoreProvider. Check the plugin " + declaringBundle); continue; } }catch(ClassNotFoundException e){ logger.error(e); } } psProviders.put(declaringBundle, data); } } } private IPreferenceNode findNode(PreferenceManager pm, String categoryId) { for (Object o : pm.getElements(PreferenceManager.POST_ORDER)) { if (o instanceof IPreferenceNode && ((IPreferenceNode) o).getId().equals(categoryId)) { return (IPreferenceNode) o; } } return null; } private String getClassURI(String definingBundleId, String spec) throws ClassNotFoundException { if (spec.startsWith("platform:")) { return spec; } // $NON-NLS-1$ return "bundleclass://" + definingBundleId + '/' + spec; } private boolean isEmpty(String value) { return value == null || value.trim().isEmpty(); } static class EmptyPreferencePage extends PreferencePage { public EmptyPreferencePage(String title) { setTitle(title); noDefaultAndApplyButton(); } @Override protected Control createContents(Composite parent) { return new Label(parent, SWT.NONE); } } } /* //package org.goko.common.preferences.internal; // //import java.util.ArrayList; //import java.util.Collection; //import java.util.Collections; //import java.util.HashMap; //import java.util.Map; // //import javax.inject.Inject; // //import org.eclipse.core.runtime.IConfigurationElement; //import org.eclipse.core.runtime.IExtensionRegistry; //import org.eclipse.core.runtime.preferences.InstanceScope; //import org.eclipse.e4.core.contexts.ContextInjectionFactory; //import org.eclipse.e4.core.contexts.IEclipseContext; //import org.eclipse.e4.core.di.annotations.Creatable; //import org.eclipse.e4.core.services.contributions.IContributionFactory; //import org.eclipse.e4.core.services.log.Logger; //import org.eclipse.jface.preference.IPreferenceNode; //import org.eclipse.jface.preference.IPreferenceStore; //import org.eclipse.jface.preference.PreferenceManager; //import org.eclipse.jface.preference.PreferenceNode; //import org.eclipse.jface.preference.PreferencePage; //import org.eclipse.swt.SWT; //import org.eclipse.swt.widgets.Composite; //import org.eclipse.swt.widgets.Control; //import org.eclipse.swt.widgets.Label; //import org.goko.common.preferences.IPreferenceStoreProvider; //import org.goko.common.preferences.ScopedPreferenceStore; // // //@Creatable //public class E4PreferenceRegistry{ ///* */ // //public static final String PREFS_PAGE = "Goko.org.goko.ui.gkPreferencesPages"; // public static final String PAGE_ID = "goko.org.ui.page.id"; // // /* */ // public static final String PREFS_PAGE_XP = "Goko.org.goko.ui.gkPreferencePage"; // $NON-NLS-1$ // public static final String PREF_STORE_PROVIDER = "Goko.org.goko.ui.gkPreferenceStoreProvider"; // $NON-NLS-1$ // protected static final String ELMT_PAGE = "page"; // $NON-NLS-1$ // protected static final String ATTR_ID = "id"; // $NON-NLS-1$ // protected static final String ATTR_CATEGORY = "category"; // $NON-NLS-1$ // protected static final String ATTR_CLASS = "class"; // $NON-NLS-1$ // protected static final String ATTR_NAME = "name"; // $NON-NLS-1$ // // protected static final String ATTR_PLUGIN_ID = "pluginId"; // $NON-NLS-1$ // protected static final String ATTR_ID_IN_WBCONTEXT = "idInWorkbenchContext"; // $NON-NLS-1$ // // @Inject // protected Logger logger; // // @Inject // protected IEclipseContext context; // // @Inject // protected IExtensionRegistry registry; // // private PreferenceManager pm = null; // // // A map of (pluginId, { IPreferenceStoreProvider, or key in wbcontext } // private Map<String, Object> psProviders; // // public PreferenceManager getPreferenceManager() // { // // // Remember of the unbounded nodes to order parent pages. // // Map<category, list of children> (all nodes except root nodes) // Map<String, Collection<IPreferenceNode>> childrenNodes = new HashMap<String, Collection<IPreferenceNode>>(); // // if (pm != null) // return pm; // // pm = new PreferenceManager(); // IContributionFactory factory = context.get(IContributionFactory.class); // // for (IConfigurationElement elmt : registry.getConfigurationElementsFor(PREFS_PAGE_XP)) // { // String bundleId = elmt.getNamespaceIdentifier(); // if (!elmt.getName().equals(ELMT_PAGE)) // { // logger.warn("unexpected element: {0}", elmt.getName()); // continue; // } else if (isEmpty(elmt.getAttribute(ATTR_ID)) || isEmpty(elmt.getAttribute(ATTR_NAME))) // { // logger.warn("missing id and/or name: {}", bundleId); // continue; // } // PreferenceNode pn = null; // if (elmt.getAttribute(ATTR_CLASS) != null) // { // PreferencePage page = null; // try // { // String prefPageURI = getClassURI(bundleId, elmt.getAttribute(ATTR_CLASS)); // Object object = factory.create(prefPageURI, context); // if (!(object instanceof PreferencePage)) // { // logger.error("Expected instance of PreferencePage: {0}", elmt.getAttribute(ATTR_CLASS)); // continue; // } // page = (PreferencePage) object; // setPreferenceStore(bundleId, page); // // } catch (ClassNotFoundException e) // { // logger.error(e); // continue; // } // ContextInjectionFactory.inject(page, context); // if ((page.getTitle() == null || page.getTitle().isEmpty()) && elmt.getAttribute(ATTR_NAME) != null) // { // page.setTitle(elmt.getAttribute(ATTR_NAME)); // } // // pn = new PreferenceNode(elmt.getAttribute(ATTR_ID), page); // } else // { // pn = new PreferenceNode(elmt.getAttribute(ATTR_ID), new EmptyPreferencePage(elmt.getAttribute(ATTR_NAME))); // } // // // Issue 2 : Fix bug on order (see : // // https://github.com/opcoach/e4Preferences/issues/2) // // Add only pages at root level and remember of child pages for // // categories // String category = elmt.getAttribute(ATTR_CATEGORY); // if (isEmpty(category)) // { // pm.addToRoot(pn); // } else // { // /* // * IPreferenceNode parent = findNode(pm, category); if (parent // * == null) { // No parent found, but may be the extension has // * not been read yet. So remember of it unboundedNodes.put(pn, // * category); } else { parent.add(pn); } // */ // // Check if this category is already registered. // Collection<IPreferenceNode> children = childrenNodes.get(category); // if (children == null) // { // children = new ArrayList<IPreferenceNode>(); // childrenNodes.put(category, children); // } // children.add(pn); // } // } // // // Must now bind pages that has not been added in nodes (depends on the // // preference page read order) // // Iterate on all possible categories // Collection<String> categoriesDone = new ArrayList<String>(); // // while (!childrenNodes.isEmpty()) // { // for (String cat : Collections.unmodifiableSet(childrenNodes.keySet())) // { // // Is this category already in preference manager ? If not add // // it later... // IPreferenceNode parent = findNode(pm, cat); // if (parent != null) // { // // Can add the list of children to this parent page... // for (IPreferenceNode pn : childrenNodes.get(cat)) // { // parent.add(pn); // } // // Ok This parent page is done. Can remove it from map // // outside of this loop // categoriesDone.add(cat); // } // } // // for (String keyToRemove : categoriesDone) // childrenNodes.remove(keyToRemove); // categoriesDone.clear(); // // } // // return pm; // } // // private void setPreferenceStore(String bundleId, PreferencePage page) // { // // Affect preference store to this page if this is a // // PreferencePage, else, must manage it internally // // Set the issue#1 on github : // // https://github.com/opcoach/e4Preferences/issues/1 // // And manage the extensions of IP // initialisePreferenceStoreProviders(); // // IPreferenceStore store = null; // // // Get the preference store according to policy. // Object data = psProviders.get(bundleId); // if (data != null) // { // if (data instanceof IPreferenceStore) // store = (IPreferenceStore) data; // else if (data instanceof IPreferenceStoreProvider) // store = ((IPreferenceStoreProvider) data).getPreferenceStore(); // else if (data instanceof String) // store = (IPreferenceStore) context.get((String) data); // // } else // { // // Default behavior : create a preference store for this bundle and remember of it // store = new ScopedPreferenceStore(InstanceScope.INSTANCE, bundleId); // psProviders.put(bundleId, store); // } // // // if (store != null) // page.setPreferenceStore(store); // else // { // logger.warn("Unable to set the preferenceStore for page " + page.getTitle() + " defined in bundle " + bundleId); // } // // } // // /** Read the e4PreferenceStoreProvider extension point */ // private void initialisePreferenceStoreProviders() // { // if (psProviders == null) // { // IContributionFactory factory = context.get(IContributionFactory.class); // // psProviders = new HashMap<String, Object>(); // // // Read extensions and fill the map... // for (IConfigurationElement elmt : registry.getConfigurationElementsFor(PREF_STORE_PROVIDER)) // { // String declaringBundle = elmt.getNamespaceIdentifier(); // String pluginId = elmt.getAttribute(ATTR_PLUGIN_ID); // if (isEmpty(pluginId)) // { // logger.warn("missing plugin Id in extension " + PREF_STORE_PROVIDER + " check the plugin " + declaringBundle); // continue; // } // // String classname = elmt.getAttribute(ATTR_CLASS); // String objectId = elmt.getAttribute(ATTR_ID_IN_WBCONTEXT); // // if ((isEmpty(classname) && isEmpty(objectId)) || (((classname != null) && classname.length() > 0) && ((objectId != null) && objectId.length() > 0))) // { // logger.warn("In extension " + PREF_STORE_PROVIDER + " only one of the two attributes (pluginId or idInWorkbenchContext) must be set. Check the plugin " // + declaringBundle); // continue; // } // // // Ok can now work with data... // Object data = objectId; // if (classname != null) // { // data = factory.create(classname, context); // if (!(data instanceof IPreferenceStoreProvider)) // { // logger.warn("In extension " + PREF_STORE_PROVIDER + " the class must implements IPreferenceStoreProvider. Check the plugin " + declaringBundle); // continue; // } // } // // psProviders.put(pluginId, data); // // } // } // } // // private IPreferenceNode findNode(PreferenceManager pm, String categoryId) // { // for (Object o : pm.getElements(PreferenceManager.POST_ORDER)) // { // if (o instanceof IPreferenceNode && ((IPreferenceNode) o).getId().equals(categoryId)) // { // return (IPreferenceNode) o; // } // } // return null; // } // // private String getClassURI(String definingBundleId, String spec) throws ClassNotFoundException // { // if (spec.startsWith("platform:")) // { // return spec; // } // $NON-NLS-1$ // return "bundleclass://" + definingBundleId + '/' + spec; // } // // private boolean isEmpty(String value) // { // return value == null || value.trim().isEmpty(); // } // // static class EmptyPreferencePage extends PreferencePage // { // // public EmptyPreferencePage(String title) // { // setTitle(title); // noDefaultAndApplyButton(); // } // // @Override // protected Control createContents(Composite parent) // { // return new Label(parent, SWT.NONE); // } // // } // //} //