这一篇博客在上一篇的基础上,实现展开/折叠功能。期待的最终效果是,双击某一Node,其后面的Node与连线都隐藏;再双击时显示回来。并且折叠之后,保存关闭,下次打开时还处于折叠状态,可以正确展开。
有一个细节应当注意,如下图:
比如折叠了节点1之后再折叠节点0,之后再展开节点0的时候,节点1应当还是处于折叠状态。
具体步骤如下:
1、为了实现这个展开/折叠操作,并且方便以后实现图标的更换,可以在节点的模型文件中添加一个布尔型的变量expanded,用于标识展开状态。可以在模型文件中修改,然后重新生成Model Code以及Edit Code,具体操作可以参考的步骤1、2。注意,将expanded的默认值设为true。
2、创建一个Command,用于实现折叠或者展开。先在diagram工程下的src目录下新建一个package,名为org.eclipse.gmf.examples.mindmap.diagram.edit.commands.custom,在其中新建一个class文件,名为ExpandOrCollapseCommand,继承自RecordingCommand。
3、ExpandOrCollapseCommand的构造函数如下,获取
public ExpandOrCollapseCommand( TransactionalEditingDomain transactionalEditingDomain, TopicEditPart topicEditPart) { super(transactionalEditingDomain); this.sourceEdgeList = ((View) topicEditPart.getModel()).getSourceEdges(); this.setLabel("Expand Or Collapse"); this.topicModel = (Topic) ((View) topicEditPart.getModel()).getElement(); this.isExpanded = topicModel.isExpanded(); this.topicEditPart = topicEditPart;}
4、重写doExecute()方法:
@Overrideprotected void doExecute() { if (this.sourceEdgeList.size() > 0) { this.topicModel.setExpanded(!this.isExpanded); this.doExpandOrCollapse(this.topicModel, this.sourceEdgeList, !this.isExpanded); }}5、最关键的doExpandOrCollapse方法代码:
/** * 执行展开或者折叠功能,并且将子节点的元素也要相应地展开或者折叠 */private void doExpandOrCollapse(Topic model, List edgeList, boolean visible) { Iteratoriter = edgeList.iterator(); while (iter.hasNext()) { Edge conn = iter.next(); conn.getTarget().setVisible(visible); Topic targetModel = (Topic) conn.getTarget().getElement(); List targetSourceEdgeList = conn.getTarget().getSourceEdges(); if (this.isExpanded) { // 如果将要折叠,则应将子节点全部隐藏 doExpandOrCollapse(targetModel, targetSourceEdgeList, false); } else if (!this.isExpanded && targetModel.isExpanded()) { // 如果将要展开,则应将子节点中,在折叠之前处于展开状态的展开 doExpandOrCollapse(targetModel, targetSourceEdgeList, true); } }}
6、接下来则要使用这个命令。由于是双击,所以先要捕获对节点的双击事件。在TopicEditPart类中重写超类中的performRequest(Request request)方法:
/** * 捕获各种事件,如双击 */@Overridepublic void performRequest(Request request) { if (request.getType() == (RequestConstants.REQ_OPEN)) { // 双击时展开或者隐藏后面的节点 Topic model = (Topic) ((View) this.getModel()).getElement(); TransactionalEditingDomain domain = TransactionUtil .getEditingDomain(this.getModel()); ExpandOrCollapseCommand command = new ExpandOrCollapseCommand( domain, this); domain.getCommandStack().execute(command); } super.performRequest(request);}
7、现在运行,会发现已经可以展开/折叠了,但是,存在一个问题:当把某一节点折叠,保存关闭后,再打开图,然后再展开这个节点,与它直接相连的节点并不会马上显示,需要保存、关闭之后再打开才会显示,如下图:
8、解决上面的问题,需要在TopicEditPart中重写getModelSourceConnections()方法。如果在超类ShapeNodeEditPart中查看原始的getModelSourceConnections()方法,最终找到ViewUtil中的getSourceConnectionsConnectingVisibleViews(View view)方法,会发现其中有一个判断:
if (edge.isVisible() && isVisible(target)){ sourceConnections.add(edge);}
而我们是要得到所有的edge,不管是否可见。我们虽然没有手动调用getModelSourceConnections(),但是在内部它是被调用的,所以,在TopicEditPart中重写getModelSourceConnections()方法如下:
/** * 重写getModelSourceConnections()方法 */@Overrideprotected List getModelSourceConnections() { View view = (View) this.getModel(); if (!view.eIsSet(NotationPackage.Literals.VIEW__SOURCE_EDGES)) return Collections.EMPTY_LIST; return view.getSourceEdges();}
9、此时再运行,则不会出现上述问题。
最终代码在