作者:王方舟
目录
Data Studio 上下文菜单管理
B y 王方舟
Data Studio 的工作流编辑器中,针对不同类型的节点,配置了不同的上下文菜单,并且实现了上下文菜单的动态构建。目前工作流当中的节点类型主要分为数据节点、算法节点、模型节点和可视化节点。其中,数据节点主要负责数据的读入、处理和处理结果表的预览;算法节点主要负责执行相应算法,读入数据并输出模型节点;模型节点以数据作为输入,输出包含预测结果的数据;可视化节点负责将输入数据转化成各式图表,对数据做可视化展现。
不同类型节点的上下文菜单如下所示:
图表 1 数据节点菜单
图表 2 算法节点菜单
图表 3 可视化节点菜单
本文将介绍 GEF 框架中的 EditorPart 上下文菜单创建流程,以及在 Data Studio 上的实践过程。
1. 上下文菜单项 Action 注册
RCP 程序的 EditorPart 中最常用主要是两类: TextEditor 和 GraphicalEditor , Eclipse 的 Editor 就是一种 TextEditor ,而 Data Studio 中的 Editor 则是后者。
GraphicalEditor 隶属 GEF 框架,与大多数图形编辑框架类似, GEF 框架也是一种 MVC 框架,此外 GEF 提供了不同的编辑部分和图案类,供用户扩展。在 GraphicalEditor 中添加上下文菜单,首先要注册菜单项的各种 Action , GraphicalEditor 类提供了 createAction 方法,注册编辑器中右键后需要展现的事件列表。父类中只提供了简单的撤销、恢复、全选、删除、保存这 5 个基本的 IAction ,如果要添加自定义 IAction ,则需要在子类里面覆写该方法,先调用父类的 createAction 方法,将父类的 5 个基本事件注册,再注册子类的事件到 ActionRegistery 对象中。
注册好的事件通过 createGraphicalViewer 方法,传给 WorkflowGraphicalViewerCreator 的实例,在其中的 createViewer 方法中,传递给 WorkflowContextMenuProvider 的上下文菜单提供器,提供注册事件列表,在该类中动态的构建上下文菜单。
2. 工作流上下文菜单提供器
工作流上下文菜单提供器中包含的成员有上述所说的事件注册列表、 WorkflowGraphicalViewerCreator 所创建的 GraphicalViewer 对象,以及鼠标右击事件的发生位置 Point ,在其继承自父类 ContextMenuProvider 的 buildContextMenu 的方法里面,通过 ID 在传递的注册事件列表拿到对应的上下文菜单 IAction ,最终形成一个完整的菜单列表。
上下文菜单提供分组的功能,通过一个 GroupID 来创建一个 Separator 对象,该对象将添加到该分组 ID 的 IAction 与其他 IAction 分隔开来,在 UI 上面体现为一条分隔线。
特别地, buildContextMenu 方法的参数为一个 IMenuManager 对象,调用该对象的 add 方法可以将 Separator 对象添加到菜单中,调用 remove 方法可以删除某个 ID 的 IAction ,调用 appendToGroup 方法可以将 IAction 对象添加到指定分组中。
3. 根据不同类型节点的右击事件构建上下文菜单
那么 ContextMenuProvider 是如何根据不同的节点类型来构建不同的菜单实例的呢?在上节所说的 GraphicalViewer 对象,可以通过 getSelectedEditParts 方法拿到当前编辑器中被用户选中的 EditParts 对象列表,当用户使用 WorkflowSelectionTool 选中了多个 EditPart 对象时,理想状态下当然不能弹出多个上下文菜单,因此在这里会取该列表的第 1 个 EditPart 作为应显示其上下文菜单的载体,当然这在用户只选择了一个 EditPart 对象时是自然的。
拿到当前所选择的 EditPart 之后,只是拿到了在图形编辑器上 UI 的对象,如果要做模型的类型区分,那必须要通过 EditPart 的 getModel 方法,拿到其中封装的模型,在 Data Studio 中,该模型对象是一个 NodeContainer 对象。
NodeContainer 在设计器中充当一层节点的容器封装,其中它的继承关系如下所示:
图表 4 NodeContainer继承关系
其中 WorkflowManager 为整个工作流中的节点集合类, SingleNodeContainer 用来表示一个节点的容器类, NativeNodeContainer 表示其本身只有一个节点,而 SubNodeContainer 中可能有多个节点,但在外部表现成一个节点(类似于一个元节点)。
特殊地,在 NativeNodeContainer 中,会封装一个 Node 对象,这个对象该容器类中封装的节点对象, getNode 之后再 getFactory 则会取到该节点对象的工厂类。
工厂类的子类从功能上区分了三种不同类型的节点,数据节点、算法节点和可视化节点的工厂类分别为 DataNodeFactory 、 AlgorithmNodeFactory 、 VizNodeFactory ,根据节点工厂类的类型,可以构建分支创建不同的上下文菜单。
4. 附录 GraphicalEditor 方法介绍
createActions() ——为该编辑器创建操作,子类应该覆盖该方法以使用 ActionRegistery 创建并注册操作。
getCommandStack() ——返回命令栈。
getEditDomain() ——返回编辑域。
initializeGraphicalViewer() ——覆盖以在 GraphicalViewer 创建后设置它的内容。
setEditDomain(DefaultEditDomain) ——为该 EditorPart 设置 EditDomain 。
Attachments:
Data Studio上下文菜单管理.docx (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
Data Studio上下文菜单管理.docx (application/vnd.openxmlformats-officedocument.wordprocessingml.document)
Data Studio上下文菜单管理.docx (application/vnd.openxmlformats-officedocument.wordprocessingml.document)