Tuesday, September 16, 2014

Using Activities in Eclipse Plugin Developments.

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.

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 ActivitiesActivities 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!!!

2 comments:

  1. Hi Sadiq.. Nice article !!

    Can you list the different possibilities to suppress the eclipse RCP menu's ? (static as well as dynamic)

    ReplyDelete
    Replies
    1. 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.

      You can also use Property Tester in many of the usecases. I will come up with this topic very soon.

      Thanks,

      Delete