親クラスもインスタンス化可能な場合、GMFマッピング定義に要注意

以下のように、KlassクラスがSuperKlassクラスを継承し、SuperKlassクラスもインスタンス化可能なモデルについて、GMFを用いてダイアグラムエディタを作成する場合、GMFマッピング定義を行う場合に注意が必要です。

結論から言うと、以下のように子クラスであるKlassクラスのマッピング定義が先にくるように、GMFマッピングを定義します。

上記と異なり、親クラスであるSuperKlassクラスのマッピング定義が先にくるようにGMFマッピングを定義してしまうと、正常に動作するダイアグラムエディタが生成されません。現象としては、子クラスであるKlassクラスのオブジェクトをキャンバス上に配置できません(SuperKlassクラスのオブジェクトは配置できます)。その理由は、生成されるXXXVisualIDRegistry.getNodeVisualID()にあります。

親クラスであるSuperKlassクラスのマッピング定義が先にくるようにGMFマッピングを定義してしまうと、XXXVisualIDRegistry.getNodeVisualID()が以下のように生成されます。

/**
 * @generated
 */
public static int getNodeVisualID(View containerView, EObject domainElement) {
	if (domainElement == null
			|| !RootEditPart.MODEL_ID
					.equals(sample.diagram.part.SampleVisualIDRegistry
							.getModelID(containerView))) {
		return -1;
	}
	switch (sample.diagram.part.SampleVisualIDRegistry
			.getVisualID(containerView)) {
	case RootEditPart.VISUAL_ID:
		if (SamplePackage.eINSTANCE.getSuperKlass().isSuperTypeOf(
				domainElement.eClass())) {
			return SuperKlassEditPart.VISUAL_ID;
		}
				if (SamplePackage.eINSTANCE.getKlass().isSuperTypeOf(
				domainElement.eClass())) {
			return KlassEditPart.VISUAL_ID;
		}
		break;
	}
	return -1;
}

このメソッドは、パレット上のボタンをクリックしキャンバス上で再度クリックしてオブジェクトを配置する際に呼ばれます。このメソッドの第2引数domainElementには、キャンバス上に追加するオブジェクトが渡されます。今回の例の場合、KlassクラスまたはSuperKlassクラスのオブジェクトが渡されます。ここで、上記コード内のswith文の中にある一つ目のif文に注目してください。SuperKlassは、Klassのスーパークラスなので、isSuperTypeOf()メソッドは、KlassおよびSuperKlassのどちらのオブジェクトが来てもtrueを返します。つまり、二つ目のif文には絶対に到達しません。その結果、常にSuperKlassEditPart.VISUAL_IDがリターンされてしまい、Klassクラスのオブジェクトはキャンバス上に配置できません。

一方、子クラスであるKlassクラスのマッピング定義が先に来るようにGMFマッピングを定義すると、XXXVisualIDRegistry.getNodeVisualID()は以下のように生成され、所望の動作をします。

/**
 * @generated
 */
public static int getNodeVisualID(View containerView, EObject domainElement) {
	if (domainElement == null
			|| !RootEditPart.MODEL_ID
					.equals(sample.diagram.part.SampleVisualIDRegistry
							.getModelID(containerView))) {
		return -1;
	}
	switch (sample.diagram.part.SampleVisualIDRegistry
			.getVisualID(containerView)) {
	case RootEditPart.VISUAL_ID:
		if (SamplePackage.eINSTANCE.getKlass().isSuperTypeOf(
				domainElement.eClass())) {
			return KlassEditPart.VISUAL_ID;
		}
		if (SamplePackage.eINSTANCE.getSuperKlass().isSuperTypeOf(
				domainElement.eClass())) {
			return SuperKlassEditPart.VISUAL_ID;
		}
		break;
	}
	return -1;
}