GEF中大部分action对位置不敏感,但还是有例外,典型的如paste,context menu中的某个action需要将clipboard中的东西paste到右键单击位置。如下图:

即使在GMF中, DiagramAction也是取得是鼠标点击paste时的位置,而不是之前右键单击出现contxt menu的位置。这里
“定点”关键是在选择paste之前
右键单击的位置已经被记住了,并且对context menu中所有对位置敏感的action都有效,比如merge, duplicate等。
下面分三步完成:
1 定义一个接口,为所有位置敏感action提供位置信息
public interface ILocationWare {
void setLocation(int x,int y);
}
2 注册一个listener到GEF editor的context menu,提供位置记忆,这个是关键。
public class LivingContextMenu extends ContextMenuProvider {
private LivingEditor editor;
private IMenuListener listener = new IMenuListener(){
@Override
public void menuAboutToShow(IMenuManager manager) {
Control canvas = getViewer().getControl();
Point cursor_location = canvas.getDisplay().getCursorLocation();
Point relative_canvas = canvas.toControl(cursor_location);
setItemLocation(manager,relative_canvas);
}
private void setItemLocation(IMenuManager manager, Point relative_canvas) {
IContributionItem[] items = manager.getItems();
for (int i =0; i < items.length; i++)
{
IContributionItem item = items[i];
if (item instanceof ActionContributionItem)
{
IAction host_action = ((ActionContributionItem)item).getAction();
if (host_action instanceof ILocationWare)
((ILocationWare)host_action).setLocation(relative_canvas.x, relative_canvas.y);
}
else if (item instanceof IMenuManager)
{
setItemLocation((IMenuManager)item, relative_canvas);
}
}
}
};
public LivingContextMenu(LivingEditor lv) {
super((GraphicalViewer)lv.getAdapter(GraphicalViewer.class));
editor = lv;
addMenuListener(listener);
}
.
.
.
@Override
public void dispose() {
removeMenuListener(listener);
super.dispose();
}
}
原理就是右键单击后,context menu的listener已经记住了鼠标在graphicalviewer control(一般为FigureCanvas)右击位置,并告知给所有context menu中对位置敏感的action。
3 对位置敏感的action实现ILocationWare接口,比如paste。
public class PasteAction extends SelectionAction implements ILocationWare {
private Point location = new Point(10,10);
private boolean contextTrigged=false;
public PasteAction(LivingEditor part) {
super(part);
}
@Override
public void run() {
//some operations depend on location
}
@Override
public void setLocation(int x, int y) {
location.setLocation(x, y);
contextTrigged = true;
}
@Override
protected void init() {
super.init();
setId(ActionFactory.PASTE.getId());
ISharedImages workbench_images = PlatformUI.getWorkbench().getSharedImages();
setImageDescriptor(workbench_images.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
setDisabledImageDescriptor(workbench_images.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
}
}
这种解决同样适用于GMF的DiagramAction。(DiagramAction也是Action的子类)