グラフのような EMF モデル用の GEF エディターを実装し、グラフ内の特定のタイプのノードに対する削除コマンドを使用しました。このセットアップを機能させるために必要なすべての手順を実行したと思います ( vainoloのブログは大きな助けになりました)。
ただし、モデル要素を削除すると、ビューが更新されません。つまり、モデル要素の図がエディター ビューから削除されず、理由がわかりません。誰かが私の情報源を見て、問題 (およびおそらく解決策:)) を指摘してくれたら、非常に感謝します。よろしくお願いします!
以下は、この問題の重要なクラスであると私が考えるものです。さらにコードを追加したり、コードを編集したりする必要がある場合は、お知らせください(ゲッターとセッター、クラス変数など、役に立たないと思われるコードは省略しました)。ありがとう!
ダイアグラム編集パーツ
public class DiagramEditPart extends AbstractGraphicalEditPart {
public DiagramEditPart(Diagram model) {
this.setModel(model);
adapter = new DiagramAdapter();
}
@Override protected IFigure createFigure() {
Figure figure = new FreeformLayer();
return figure;
}
@Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramXYLayoutPolicy());
}
@Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
if (((Diagram) getModel()).getMyNodes() != null)
allModelObjects.addAll(((Diagram) getModel()).getMyNodes());
return allModelObjects;
}
@Override public void activate() {
if(!isActive()) {
((Diagram) getModel()).eAdapters().add(adapter);
}
super.activate();
}
@Override public void deactivate() {
if(isActive()) {
((Diagram) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class DiagramAdapter implements Adapter {
@Override public void notifyChanged(Notification notification) {
switch (notification.getEventType()) {
case Notification.REMOVE: refreshChildren();
break;
default:
break;
}
}
@Override public Notifier getTarget() {
return (Diagram) getModel();
}
@Override public void setTarget(Notifier newTarget) {
// Do nothing.
}
@Override public boolean isAdapterForType(Object type) {
return type.equals(Diagram.class);
}
}
}
MyNodeEditPart
public class MyNodeEditPart extends AbstractGraphicalEditPart {
public MyNodeEditPart(MyNode model) {
this.setModel(model);
adapter = new MyNodeAdapter();
}
@Override protected IFigure createFigure() {
return new MyNodeFigure();
}
@Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.COMPONENT_ROLE, new MyNodeComponentEditPolicy());
}
@Override protected void refreshVisuals() {
MyNodeFigure figure = (MyNodeFigure) getFigure();
DiagramEditPart parent = (DiagramEditPart) getParent();
Dimension labelSize = figure.getLabel().getPreferredSize();
Rectangle layout = new Rectangle((getParent().getChildren().indexOf(this) * 50),
(getParent().getChildren().indexOf(this) * 50), (labelSize.width + 20),
(labelSize.height + 20));
parent.setLayoutConstraint(this, figure, layout);
}
public List<Edge> getModelSourceConnections() {
if ((MyNode) getModel() != null && ((MyNode) getModel()).getDiagram() != null) {
ArrayList<Edge> sourceConnections = new ArrayList<Edge>();
for (Edge edge : ((MyNode) getModel()).getDiagram().getOutEdges(((MyNode) getModel()).getId())) {
sourceConnections.add(edge);
}
return sourceConnections;
}
return null;
}
// + the same method for targetconnections
@Override public void activate() {
if (!isActive()) {
((MyNode) getModel()).eAdapters().add(adapter);
}
super.activate();
}
@Override public void deactivate() {
if (isActive()) {
((MyNode) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class MyNodeAdapter implements Adapter {
@Override
public void notifyChanged(Notification notification) {
refreshVisuals();
}
@Override
public Notifier getTarget() {
return (MyNode) getModel();
}
@Override
public void setTarget(Notifier newTarget) {
// Do nothing
}
@Override
public boolean isAdapterForType(Object type) {
return type.equals(MyNode.class);
}
}
}
MyNodeComponentEditPolicy
public class MyNodeComponentEditPolicy extends ComponentEditPolicy {
@Override
protected Command createDeleteCommand(GroupRequest deleteRequest) {
DeleteMyNodeCommand nodeDeleteCommand = new DeleteMyNodeCommand((MyNode) getHost().getModel());
return nodeDeleteCommand;
}
}
DeleteMyNodeCommand
public class DeleteMyNodeCommand extends Command {
public DeleteMyNodeCommand(MyNode model) {
this.node = model;
this.graph = node.getDiagram();
}
@Override public void execute() {
getMyNode().setDiagram(null);
System.out.println("Is the model still present in the graph? " + getGraph().getMyNodes().contains(getMyNode()));
// Returns false, i.e., graph doesn't contain model object at this point!
}
@Override public void undo() {
getMyNode().setDiagram(getGraph());
}
}
編集
Re execc のコメント: はい、refreshChildren()
呼び出されています。System.err
ノードの削除時にコンソールに表示される単純な行をオーバーライドして追加することで、これをテストしました。
@Override
public void refreshChildren() {
super.refreshChildren();
System.err.println("refreshChildren() IS being called!");
}
編集2
面白い (まあ...) ことは、エディターを閉じてモデルを永続化してから、同じファイルを再度開くと、ノードがペイントされなくなり、モデルに存在しないことです。しかし、これはどういう意味ですか?古いモデルに取り組んでいますか? または、モデルの子の更新/取得が正しく機能していませんか?
編集3
私が抱えている問題を説明するかもしれない奇妙なものを見つけましたか? getModelChildren()
メソッドで を呼び出し、変更不可能allModelObjects.addAll(((Diagram) getModel()).getMyNodes());
なをgetMyNodes()
返します。削除コマンドの行に沿って何かをしようとしたときにわかりました...うーん。 EList
((Diagram) getModel()).getMyNodes().remove(getMyNode())
UnsupportedOperationException
編集4
ええと、誰か私を殺してください?常に同じオブジェクトを扱っているかどうかを再確認しましたが、これを行っているときに、非常に恥ずかしいことDiagram
に遭遇しました。
最後のバージョンのgetModelChildren()
メソッドはDiagramEditPart
約を読みました。このような:
@Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
for (MyNode node : nodes) {
if (node.getDiagram() != null); // ### D'Uh! ###
allModelObjects.add(node);
}
return allModelObjects;
}
みんなの時間を盗んでしまったことをお詫びします!あなたの提案は非常に役に立ち、最終的にバグを追跡するのに役立ちました!
また、いくつかの教訓を学びました。その中には、必ず元のコードを貼り付けてください。単純化しすぎると、バグが隠れてしまう可能性があります。また、EMF、Adapter
、および GEF について多くのことを学びました。まだ: