Eclipse RCP: declarative actions

Source: Internet
Author: User
I encountered a problem when I was working on an eclipse RCP project. The customer needs to implement a popup menu on a tree, in which the menu item varies depending on the right-click Tree node. Popup menu extension is easy to implement. You only need to add an objectcontribution. Different actions are displayed based on different tree node types. Another requirement is very troublesome. The menu item also needs to be different based on the user's perspective. Objectcontribution does not have such a detailed declaration item, and it seems that only programming is completed. Popup menu actions can implement two interfaces, except for the iworkbenchwindowactiondelegate of a common Declarative action, and iobjectactiondelegate. In the eclipse RCP book of Addison Wesley, The setactivepart () method of this interface is called every time you open the popup menu. You can remove the undesired actions disable at this time. I tried it. Why? In addition, the ordinary iworkbenchwindowactiondelegate selectionchanged () method does not seem easy to use. After mining the eclipse UI source code, I finally figured out that it was almost a pitfall of eclispe RCP. Iactiondelegate (parent interface of iworkbenchwindowactiondelegate, "The workbench will generate a proxy action object on behalf of the plug-in to avoid having to activate the plug-in until the user needs it. if the action is saved med the workbench will load the class that implements this interface and create what is called an action delegate object. this seems to make sense. However, one side-effect is the callback method written in delegate and cannot be called easily. First, you must understand what proxy action is and what delegate object is. Proxy action is a traditional jface action that users actually see in the UI. For example, a menu item and a button on the toolbar. The delegate object is written in iactiondelegate, which is actually implemented for the Declarative action. Here the problem is: whether it is setactivepart () or selectionchanged (), we write them in the delegate object, but the action is not perform, and this object will not be created, of course, our method will not be executed. Check the source code: org. Eclipse. UI. Internal. pluginaction # runwithevent ():
 
If (delegate = NULL )...{
Createdelegate ();
//...
}
Delegate. Run (this); in most cases, this method calls the action delegate we wrote. Obviously, the framework will not generate it until we have to use our action delegate. Then let's take a look at the setactivepart () of iobjectactiondelegate. When the right-click menu is about to pop up, the menuabouttoshow event of menumanager of jface is triggered, and the event streams to Org. eclipse. UI. internal. objectactioncontributor # contributeobjectactions (), which is a part of our concern. Here, we first determine whether the current selection (context of the context menu) is suitable for the object type declared in objectcontribution, hide the unsuitable action, and then try to call setactivepart ():

If (Ad. getaction () instanceof objectpluginaction )...{
Final objectpluginaction action = (objectpluginaction) ad. getaction ();
Isaferunnable runnable = new isaferunnable ()...{
//...
Public void run () throws exception ...{
Action. setactivepart (part );
Action. selectionchanged (selection );
}
};
Saferunner. Run (runnable );
} The actual type of the header action here is org. Eclipse. UI. Internal. objectpluginaction. Its setactivepart () method includes:

If (actiondelegate instanceof iobjectactiondelegate & activepart! = NULL ){
Final iobjectactiondelegate objectactiondelegate = (iobjectactiondelegate) actiondelegate;
Final isaferunnable runnable = new isaferunnable (){
Public void run () throws exception {
Objectactiondelegate. setactivepart (objectpluginaction. This, activepart );
}
//...
}
Actiondelegate is the proxy action class we write. Obviously, if it is empty, the content in it cannot be called for the setactivepart () method we write, and this is the status before we trigger this action. Finally, let's look at the selectionchanged () of iactiondelegate. This callback function can respond to the selection information provided by selectionprovider in the view. The callback function takes effect only when the menu item is viewcontributor. Under normal circumstances, the selection event in the view is, all callback functions are called. (In the above discussion about setactivepart (), selectionchanged () is also called, but this is not counted. selectionchanged () is called only when the right-click menu is displayed, we need it to make a response to every selection, regardless of the left-click button .) First, register selectionprovider on the current iworkbrenchpagesite so that the selection event of our provider can affect our action. The common selectionprovider is the various viewer in jface. It is called in the viewpart implementation:

Getsite (). setselectionprovider (treeviewer); in this way, our view can respond to the treeviewer selection event. The event is sent from the viewer and will go all the way to org. Eclipse. UI. Internal. pluginaction (the objectpluginaction is a subclass of it). We can see in its method selectionchanged:

If (delegate = NULL & isoktocreatedelegate ())...{
Createdelegate ();
} Else ...{
Refreshenablement ();
}
It seems that if our proxy has not been created, it will help us create it, but it is slow. The isoktocreatedelegate () method writes:

If (getstyle () = iaction. as_drop_down_menu &&! Wwinpluginpulldown. Class. isinstance (this ))...{
Return true;
}
// Test if the plugin has loaded
String bundleid = configelement. getnamespace ();
Return bundleutility. isactive (bundleid );
That is, if our action is drop down menu item, it will be created, or the plug-in to which the action belongs has been loaded, it will be created. For default actions, these judgments will not pass. So our action is still not created. In refreshenablement (), there are: If (delegate! = NULL )...{
Delegate. selectionchanged (this, selection );
}
The empty delegate is ignored. In short, be careful about the actions declared in RCP. The callback function we write is not always called. Before an action is actually activated, our proxy class (in most cases) will not be automatically created. The solution to this problem is actually available. As long as isoktocreatedelegate () returns true, the proxy class can be automatically created. After testing, the style of the action can be set to pulldown as long as it is declared. In this way, as long as the right-click menu is displayed or the selection event is sent, the proxy class will be created and the callback will always be called.
Perspective? Out of my preference for Declarative Programming, I prefer declarative actions. However, it is obvious that declarative actions is not suitable for the customer's needs. We need to judge the current perspective in the callback of each action and then decide whether to make it available. This is very troublesome programming, following the dry principle, we should program actions directly. Why? The bias towards eclipse makes me think this is a problem with the customer's needs. Eclipse's declarative actions is a self-consistent system. Whether an action is available depends only on its current minimum context. In our project, it is related to the type of the selected tree node, and the state of the entire system, for example, the current perspective should not be the main consideration of action. Moreover, perspective should not be used as the basis for task division. The definition of perspective in eclipse RCP is just a "screen page template", which records a set of default views and their layout, as a convenient choice for users. It is not even within the inheritance structure of the UI components of eclipse RCP, but a logical concept of a collection of UI components. The basic UI component for real function execution should be view. In eclipse, we can see at any time that IDE prompts us to switch to perspective, but we never see that an action can only be used in this perspective but not in another one. For example, after the debug function is enabled, the IDE will tell us to switch to debug perspective. However, "all views in this perspective and all functions can be used in the Java view and in the PD view, in the resources view. Only debug perspective enables a set of default views and maintains a set of default la S. To diversify user functions, we should implement different views and different right-click menus on different views. If the two views have repeated functions, you should also consider using a modular UI component, rather than determining the different performance of the same view based on perspective.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.