Using Activities in Eclipse Plugin Developments.
First lets understand Activities in Eclipse World.
An activity is a logical grouping of functionality that is centered around a certain kind of task. This means we can group few functionality with any kind of task and can identify that group of functionality with an activity.
Let us understand this with an example. Lets suppose you want to filter some functionality depending on some scenario or permission or business requirement.Here we can use activities. I will demonstrate this with live code here.
1. Requirement: There is are few menu items present in File menu. And on click of toggle button in Run Menu, I want to hide/show menu items in File Menu.
There are 2 ways of doing this using Activities.
a) Conventional Activities:
b) Expression Based Activities.
a) Conventional Activities: It is the general way in which we define activity in plugin.xml
and then use WorkbenchActivitySupport to set those activities which has to be enabled.
and then use WorkbenchActivitySupport to set those activities which has to be enabled.
Defining activities
Activities are defined using the org.eclipse.ui.activities extension point.
<extension
point="org.eclipse.ui.activities">
<activity
id="TestActivities.customActivity"
name="CustomActivity">
</activity>
<activityPatternBinding
activityId="TestActivities.customActivity"
pattern="TestActivities/org.eclipse.ui.file.import">
</activityPatternBinding>
</extension>
Activity has:
id: Give it a unique name.
name: Give it some name.
Now bind this activity with a functionality. Here we have done with org.eclipse.ui.file.import identifier.
An activity-pattern binding associates an activity with a regular expression that is used to match identifiers. The syntax of the regular expressions conforms to the usage defined in java.util.regex.Pattern. The identifiers describing functionality that can be filtered from the UI are of the form <plugin-id>/<local-id> or simply <local-id>.
Similarly we can associate activity with some category using <categoryActivityBinding> and associate with another activity also using <activityRequirementBinding>.
Activity pattern bindings can be used to associate large groups of contributions with a particular activity, or to associate very specific contributions with an activity like :
- Views and editors
- Perspectives
- Preference and property pages
- Menus and toolbars
- New wizard
- Common Navigator Action Providers
Now once we have set the above Activity, we need to use API to enable/disable the desired Activity and enable/disable its associated functionality.
Here I am taking an example , in which I have a Run Menu and it contains a menu item named 'ToggleFileImport' and this button will toggle(show/hide) Import menu item present in File menu.
I have created a commandHandler for 'ToggleFileImport' menu item.
public class CustomHandlerForActivity extends AbstractHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
disableRun();
return null;
}
private void disableRun() {
IWorkbench iWorkbench = PlatformUI.getWorkbench();
IWorkbenchActivitySupport activitySupport = iWorkbench.getActivitySupport();
IActivityManager activityManager = activitySupport.getActivityManager();
Set<String> enabledActivityIds = new HashSet<String>
(activityManager.getEnabledActivityIds());
Set<String> definedActivityIds = activityManager.getDefinedActivityIds();
System.out.println(definedActivityIds);
System.out.println(enabledActivityIds);
Iterator<String> iterator = enabledActivityIds.iterator();
boolean activityEnabled=false;
IActivity activity = activityManager.getActivity("TestActivities.customActivity");
if(activity.isEnabled()){
enabledActivityIds.remove("TestActivities.customActivity");
}
else{
enabledActivityIds.add("TestActivities.customActivity");
}
activitySupport.setEnabledActivityIds(enabledActivityIds);
}
}
Here we can see that IWorkbenchActivitySupport is responsible for setting the list of enabled Activity ids.
b) Expression Based Activities : Activities that filter out UI elements which are not supposed to be shown to the user (e.g. based on their access rights) will be called expression-based activities.
Here I have implemented which a sample expression which is set by clicking a menu Item.
It is similar to the above example , in which I have a Run Menu and it contains a menu item named 'TogglePrint' and this button will toggle(show/hide) Print menu item present in File menu by enabling and disabling the activity.
<activity
id="TestActivities.activity3"
name="RemovePrintActivity">
<enabledWhen>
<with
variable="isCommadToTogglePrintMenu">
<equals
value="enabled">
</equals>
</with>
</enabledWhen>
</activity>
<activityPatternBinding
activityId="TestActivities.activity3"
pattern="TestActivities/org.eclipse.ui.file.print">
</activityPatternBinding>
Here you can see <enabledWhen>, to set an expression for its enabling.
<extension
point="org.eclipse.ui.commands">
<command
defaultHandler="testactivities.CustomHandlerForActivity"
id="TestActivities.testCommand"
name="TestCommand">
</command>
<command
defaultHandler="testactivities.TogglePrintHandler"
id="TestActivities.togglePrint"
name="TogglePrint">
</command>
</extension>
<extension
point="org.eclipse.ui.services">
<sourceProvider
provider="testactivities.CustomSourceProvider">
<variable
name="isCommadToTogglePrintMenu"
priorityLevel="workbench">
</variable>
</sourceProvider>
</extension>
Here you can see that I am using "org.eclipse.ui.services" extension point to set expression value using source provider.
public class CustomSourceProvider extends AbstractSourceProvider {
public final static String TOGGLE_PRINT = "isCommadToTogglePrintMenu";
private final static Map<String, String> stateMap = new HashMap<String,String>();
private final static String[] PROVIDED_SOURCE_NAMES = new String[] { TOGGLE_PRINT };
public final static String ENABLED = "enabled";
public final static String DISENABLED = "disabled";
private boolean enabled = true;
public CustomSourceProvider() {
// TODO Auto-generated constructor stub
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
@Override
public Map getCurrentState() {
stateMap.put(TOGGLE_PRINT, "enabled");
return stateMap;
}
@Override
public String[] getProvidedSourceNames() {
return PROVIDED_SOURCE_NAMES;
}
public void toogleEnabled() {
enabled = !enabled ;
String value = enabled ? ENABLED : DISENABLED;
fireSourceChanged(ISources.WORKBENCH, TOGGLE_PRINT, value);
}
}
public class TogglePrintHandler extends AbstractHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
ISourceProviderService sourceProviderService = (ISourceProviderService) HandlerUtil
.getActiveWorkbenchWindow(event).getService(ISourceProviderService.class);
// now get my service
CustomSourceProvider provider = (CustomSourceProvider) sourceProviderService
.getSourceProvider(CustomSourceProvider.TOGGLE_PRINT);
provider.toogleEnabled();
return null;
}
}
So we can see that Activities can be used on both ways and can be implemented.
Full Sample code can be accessed from following location:
https://github.com/sanjar/Day_Today/tree/master/TestActivities
Your suggestions and queries are invited....
CHEERS!!!
Hi Sadiq.. Nice article !!
ReplyDeleteCan you list the different possibilities to suppress the eclipse RCP menu's ? (static as well as dynamic)
Yeah you can have other way to suppress contribution using Equinox Transforms. You can have a look on my blog - http://eclipse-api-inside-story.blogspot.in/2014/09/equinox-transform-revealed.html.
DeleteYou can also use Property Tester in many of the usecases. I will come up with this topic very soon.
Thanks,