GMF树形布局 2 实现展开/折叠

这一篇博客在上一篇的基础上,实现展开/折叠功能。期待的最终效果是,双击某一Node,其后面的Node与连线都隐藏;再双击时显示回来。而且折叠以后,保存关闭,下次打开时还处于折叠状态,能够正确展开。 dom

有一个细节应当注意,以下图: eclipse

好比折叠了节点1以后再折叠节点0,以后再展开节点0的时候,节点1应当仍是处于折叠状态。 ide

具体步骤以下: 函数

一、为了实现这个展开/折叠操做,而且方便之后实现图标的更换,能够在节点的模型文件中添加一个布尔型的变量expanded,用于标识展开状态。能够在模型文件中修改,而后从新生成Model Code以及Edit Code,具体操做能够参考这里的步骤一、2。注意,将expanded的默认值设为true。 this

二、建立一个Command,用于实现折叠或者展开。先在diagram工程下的src目录下新建一个package,名为org.eclipse.gmf.examples.mindmap.diagram.edit.commands.custom,在其中新建一个class文件,名为ExpandOrCollapseCommand,继承自RecordingCommand。 spa

三、ExpandOrCollapseCommand的构造函数以下,获取 .net

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;
}

四、重写doExecute()方法: code

@Override
protected void doExecute() {
    if (this.sourceEdgeList.size() > 0) {
        this.topicModel.setExpanded(!this.isExpanded);
        this.doExpandOrCollapse(this.topicModel, this.sourceEdgeList, !this.isExpanded);
    }
}
五、最关键的doExpandOrCollapse方法代码:
/**
 * 执行展开或者折叠功能,而且将子节点的元素也要相应地展开或者折叠
 */
private void doExpandOrCollapse(Topic model, List edgeList, boolean visible) {
    Iterator<ConnectorImpl> iter = 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);
        }
    }
}

六、接下来则要使用这个命令。因为是双击,因此先要捕获对节点的双击事件。在TopicEditPart类中重写超类中的performRequest(Request request)方法: orm

/**
 * 捕获各类事件,如双击
 */
@Override
public 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);
}

七、如今运行,会发现已经能够展开/折叠了,可是,存在一个问题:当把某一节点折叠,保存关闭后,再打开图,而后再展开这个节点,与它直接相连的节点并不会立刻显示,须要保存、关闭以后再打开才会显示,以下图: blog


八、解决上面的问题,须要在TopicEditPart中重写getModelSourceConnections()方法。若是在超类ShapeNodeEditPart中查看原始的getModelSourceConnections()方法,最终找到ViewUtil中的getSourceConnectionsConnectingVisibleViews(View view)方法,会发现其中有一个判断:

if (edge.isVisible() && isVisible(target)){
    sourceConnections.add(edge);
}

而咱们是要获得全部的edge,不论是否可见。咱们虽然没有手动调用getModelSourceConnections(),可是在内部它是被调用的,因此TopicEditPart中重写getModelSourceConnections()方法以下:

/**
 * 重写getModelSourceConnections()方法
 */
@Override
protected List getModelSourceConnections() {
    View view = (View) this.getModel();
    if (!view.eIsSet(NotationPackage.Literals.VIEW__SOURCE_EDGES))
        return Collections.EMPTY_LIST;
    return view.getSourceEdges();
}

九、此时再运行,则不会出现上述问题。

最终代码在这里

双子座@开源中国

相关文章
相关标签/搜索