1 /******************************************************************************* 2 * Copyright (c) 2000, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 15 package org.eclipse.ui.internal.activities; 16 17 import java.util.ArrayList; 18 import java.util.Collections; 19 import java.util.Iterator; 20 import java.util.List; 21 import org.eclipse.core.expressions.Expression; 22 import org.eclipse.core.expressions.ExpressionConverter; 23 import org.eclipse.core.runtime.CoreException; 24 import org.eclipse.core.runtime.IConfigurationElement; 25 import org.eclipse.core.runtime.IExtension; 26 import org.eclipse.core.runtime.IExtensionDelta; 27 import org.eclipse.core.runtime.IExtensionRegistry; 28 import org.eclipse.core.runtime.IStatus; 29 import org.eclipse.core.runtime.Status; 30 import org.eclipse.jface.preference.IPreferenceStore; 31 import org.eclipse.ui.PlatformUI; 32 import org.eclipse.ui.internal.WorkbenchPlugin; 33 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; 34 import org.eclipse.ui.internal.util.ConfigurationElementMemento; 35 import org.eclipse.ui.statushandlers.StatusManager; 36 37 final class ExtensionActivityRegistry extends AbstractActivityRegistry { 38 39 /** 40 * Prefix for all activity preferences 41 */ 42 private static final String PREFIX = "UIActivities."; //$NON-NLS-1$ 43 44 private List<ActivityRequirementBindingDefinition> activityRequirementBindingDefinitions; 45 46 private List<ActivityDefinition> activityDefinitions; 47 48 private List<ActivityPatternBindingDefinition> activityPatternBindingDefinitions; 49 50 private List<CategoryActivityBindingDefinition> categoryActivityBindingDefinitions; 51 52 private List<CategoryDefinition> categoryDefinitions; 53 54 private List<String> defaultEnabledActivities; 55 56 private IExtensionRegistry extensionRegistry; 57 ExtensionActivityRegistry(IExtensionRegistry extensionRegistry)58 ExtensionActivityRegistry(IExtensionRegistry extensionRegistry) { 59 if (extensionRegistry == null) { 60 throw new NullPointerException(); 61 } 62 63 this.extensionRegistry = extensionRegistry; 64 65 this.extensionRegistry.addRegistryChangeListener(registryChangeEvent -> { 66 IExtensionDelta[] extensionDeltas = registryChangeEvent.getExtensionDeltas(Persistence.PACKAGE_PREFIX, 67 Persistence.PACKAGE_BASE); 68 69 if (extensionDeltas.length != 0) { 70 load(); 71 } 72 }); 73 74 load(); 75 } 76 getNamespace(IConfigurationElement configurationElement)77 private String getNamespace(IConfigurationElement configurationElement) { 78 String namespace = null; 79 80 if (configurationElement != null) { 81 IExtension extension = configurationElement.getDeclaringExtension(); 82 83 if (extension != null) { 84 namespace = extension.getContributor().getName(); 85 } 86 } 87 88 return namespace; 89 } 90 91 /** 92 * Returns the activity definition found at this id. 93 * 94 * @param id <code>ActivityDefinition</code> id. 95 * @return <code>ActivityDefinition</code> with given id or <code>null</code> if 96 * not found. 97 */ getActivityDefinitionById(String id)98 private ActivityDefinition getActivityDefinitionById(String id) { 99 int size = activityDefinitions.size(); 100 for (int i = 0; i < size; i++) { 101 ActivityDefinition activityDef = activityDefinitions.get(i); 102 if (activityDef.getId().equals(id)) { 103 return activityDef; 104 } 105 } 106 return null; 107 } 108 load()109 private void load() { 110 if (activityRequirementBindingDefinitions == null) { 111 activityRequirementBindingDefinitions = new ArrayList<>(); 112 } else { 113 activityRequirementBindingDefinitions.clear(); 114 } 115 116 if (activityDefinitions == null) { 117 activityDefinitions = new ArrayList<>(); 118 } else { 119 activityDefinitions.clear(); 120 } 121 122 if (activityPatternBindingDefinitions == null) { 123 activityPatternBindingDefinitions = new ArrayList<>(); 124 } else { 125 activityPatternBindingDefinitions.clear(); 126 } 127 128 if (categoryActivityBindingDefinitions == null) { 129 categoryActivityBindingDefinitions = new ArrayList<>(); 130 } else { 131 categoryActivityBindingDefinitions.clear(); 132 } 133 134 if (categoryDefinitions == null) { 135 categoryDefinitions = new ArrayList<>(); 136 } else { 137 categoryDefinitions.clear(); 138 } 139 140 if (defaultEnabledActivities == null) { 141 defaultEnabledActivities = new ArrayList<>(); 142 } else { 143 defaultEnabledActivities.clear(); 144 } 145 146 IConfigurationElement[] configurationElements = extensionRegistry 147 .getConfigurationElementsFor(Persistence.PACKAGE_FULL); 148 149 for (IConfigurationElement configurationElement : configurationElements) { 150 String name = configurationElement.getName(); 151 152 switch (name) { 153 case Persistence.TAG_ACTIVITY_REQUIREMENT_BINDING: 154 readActivityRequirementBindingDefinition(configurationElement); 155 break; 156 case Persistence.TAG_ACTIVITY: 157 readActivityDefinition(configurationElement); 158 break; 159 case Persistence.TAG_ACTIVITY_PATTERN_BINDING: 160 readActivityPatternBindingDefinition(configurationElement); 161 break; 162 case Persistence.TAG_CATEGORY_ACTIVITY_BINDING: 163 readCategoryActivityBindingDefinition(configurationElement); 164 break; 165 case Persistence.TAG_CATEGORY: 166 readCategoryDefinition(configurationElement); 167 break; 168 case Persistence.TAG_DEFAULT_ENABLEMENT: 169 readDefaultEnablement(configurationElement); 170 break; 171 default: 172 break; 173 } 174 } 175 176 // merge enablement overrides from plugin_customization.ini 177 IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); 178 for (ActivityDefinition activityDef : activityDefinitions) { 179 String id = activityDef.getId(); 180 String preferenceKey = createPreferenceKey(id); 181 if ("".equals(store.getDefaultString(preferenceKey))) //$NON-NLS-1$ 182 continue; 183 if (store.getDefaultBoolean(preferenceKey)) { 184 if (!defaultEnabledActivities.contains(id) && activityDef.getEnabledWhen() == null) 185 defaultEnabledActivities.add(id); 186 } else { 187 defaultEnabledActivities.remove(id); 188 } 189 } 190 191 // Removal of all defaultEnabledActivites which target to expression 192 // controlled activities. 193 for (int i = 0; i < defaultEnabledActivities.size();) { 194 String id = defaultEnabledActivities.get(i); 195 ActivityDefinition activityDef = getActivityDefinitionById(id); 196 if (activityDef != null && activityDef.getEnabledWhen() != null) { 197 defaultEnabledActivities.remove(i); 198 StatusManager.getManager().handle(new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, 199 "Default enabled activity declarations will be ignored (id: " + id + ")")); //$NON-NLS-1$ //$NON-NLS-2$ 200 } else { 201 i++; 202 } 203 } 204 205 // remove all requirement bindings that reference expression-bound activities 206 for (Iterator<ActivityRequirementBindingDefinition> i = activityRequirementBindingDefinitions.iterator(); i 207 .hasNext();) { 208 ActivityRequirementBindingDefinition bindingDef = i.next(); 209 ActivityDefinition activityDef = getActivityDefinitionById(bindingDef.getRequiredActivityId()); 210 if (activityDef != null && activityDef.getEnabledWhen() != null) { 211 i.remove(); 212 StatusManager.getManager().handle(new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, 213 "Expression activity cannot have requirements (id: " + activityDef.getId() + ")")); //$NON-NLS-1$ //$NON-NLS-2$ 214 continue; 215 } 216 217 activityDef = getActivityDefinitionById(bindingDef.getActivityId()); 218 if (activityDef != null && activityDef.getEnabledWhen() != null) { 219 i.remove(); 220 StatusManager.getManager().handle(new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, 221 "Expression activity cannot be required (id: " + activityDef.getId() + ")")); //$NON-NLS-1$ //$NON-NLS-2$ 222 } 223 } 224 225 boolean activityRegistryChanged = false; 226 227 if (!activityRequirementBindingDefinitions.equals(super.activityRequirementBindingDefinitions)) { 228 super.activityRequirementBindingDefinitions = Collections 229 .unmodifiableList(new ArrayList<>(activityRequirementBindingDefinitions)); 230 activityRegistryChanged = true; 231 } 232 233 if (!activityDefinitions.equals(super.activityDefinitions)) { 234 super.activityDefinitions = Collections.unmodifiableList(new ArrayList<>(activityDefinitions)); 235 activityRegistryChanged = true; 236 } 237 238 if (!activityPatternBindingDefinitions.equals(super.activityPatternBindingDefinitions)) { 239 super.activityPatternBindingDefinitions = Collections 240 .unmodifiableList(new ArrayList<>(activityPatternBindingDefinitions)); 241 activityRegistryChanged = true; 242 } 243 244 if (!categoryActivityBindingDefinitions.equals(super.categoryActivityBindingDefinitions)) { 245 super.categoryActivityBindingDefinitions = Collections 246 .unmodifiableList(new ArrayList<>(categoryActivityBindingDefinitions)); 247 activityRegistryChanged = true; 248 } 249 250 if (!categoryDefinitions.equals(super.categoryDefinitions)) { 251 super.categoryDefinitions = Collections.unmodifiableList(new ArrayList<>(categoryDefinitions)); 252 activityRegistryChanged = true; 253 } 254 255 if (!defaultEnabledActivities.equals(super.defaultEnabledActivities)) { 256 super.defaultEnabledActivities = Collections.unmodifiableList(new ArrayList<>(defaultEnabledActivities)); 257 activityRegistryChanged = true; 258 } 259 260 if (activityRegistryChanged) { 261 fireActivityRegistryChanged(); 262 } 263 } 264 265 /** 266 * Create the preference key for the activity. 267 * 268 * @param activityId the activity id. 269 * @return String a preference key representing the activity. 270 */ createPreferenceKey(String activityId)271 private String createPreferenceKey(String activityId) { 272 return PREFIX + activityId; 273 } 274 readDefaultEnablement(IConfigurationElement configurationElement)275 private void readDefaultEnablement(IConfigurationElement configurationElement) { 276 String enabledActivity = Persistence 277 .readDefaultEnablement(new ConfigurationElementMemento(configurationElement)); 278 279 if (enabledActivity != null) { 280 defaultEnabledActivities.add(enabledActivity); 281 } 282 283 } 284 readActivityRequirementBindingDefinition(IConfigurationElement configurationElement)285 private void readActivityRequirementBindingDefinition(IConfigurationElement configurationElement) { 286 ActivityRequirementBindingDefinition activityRequirementBindingDefinition = Persistence 287 .readActivityRequirementBindingDefinition(new ConfigurationElementMemento(configurationElement), 288 getNamespace(configurationElement)); 289 290 if (activityRequirementBindingDefinition != null) { 291 activityRequirementBindingDefinitions.add(activityRequirementBindingDefinition); 292 } 293 } 294 readActivityDefinition(IConfigurationElement configurationElement)295 private void readActivityDefinition(IConfigurationElement configurationElement) { 296 ActivityDefinition activityDefinition = Persistence.readActivityDefinition( 297 new ConfigurationElementMemento(configurationElement), getNamespace(configurationElement)); 298 299 if (activityDefinition != null) { 300 // this is not ideal, but core expressions takes an 301 // IConfigurationElement or a w3c dom Document 302 IConfigurationElement[] enabledWhen = configurationElement 303 .getChildren(IWorkbenchRegistryConstants.TAG_ENABLED_WHEN); 304 if (enabledWhen.length == 1) { 305 IConfigurationElement[] expElement = enabledWhen[0].getChildren(); 306 if (expElement.length == 1) { 307 try { 308 Expression expression = ExpressionConverter.getDefault().perform(expElement[0]); 309 activityDefinition.setEnabledWhen(expression); 310 } catch (CoreException e) { 311 StatusManager.getManager().handle(e, WorkbenchPlugin.PI_WORKBENCH); 312 } 313 } 314 } 315 activityDefinitions.add(activityDefinition); 316 } 317 } 318 readActivityPatternBindingDefinition(IConfigurationElement configurationElement)319 private void readActivityPatternBindingDefinition(IConfigurationElement configurationElement) { 320 ActivityPatternBindingDefinition activityPatternBindingDefinition = Persistence 321 .readActivityPatternBindingDefinition(new ConfigurationElementMemento(configurationElement), 322 getNamespace(configurationElement)); 323 324 if (activityPatternBindingDefinition != null) { 325 activityPatternBindingDefinitions.add(activityPatternBindingDefinition); 326 } 327 } 328 readCategoryActivityBindingDefinition(IConfigurationElement configurationElement)329 private void readCategoryActivityBindingDefinition(IConfigurationElement configurationElement) { 330 CategoryActivityBindingDefinition categoryActivityBindingDefinition = Persistence 331 .readCategoryActivityBindingDefinition(new ConfigurationElementMemento(configurationElement), 332 getNamespace(configurationElement)); 333 334 if (categoryActivityBindingDefinition != null) { 335 categoryActivityBindingDefinitions.add(categoryActivityBindingDefinition); 336 } 337 } 338 readCategoryDefinition(IConfigurationElement configurationElement)339 private void readCategoryDefinition(IConfigurationElement configurationElement) { 340 CategoryDefinition categoryDefinition = Persistence.readCategoryDefinition( 341 new ConfigurationElementMemento(configurationElement), getNamespace(configurationElement)); 342 343 if (categoryDefinition != null) { 344 categoryDefinitions.add(categoryDefinition); 345 } 346 } 347 } 348