メインコンテンツまでスキップ

モデル編集操作時の動的制約の追加

プレビュー公開

本機能および本機能で利用する API は先行公開しているものです。 現時点で品質保証しておりませんので、ご利用される場合はユーザー様の責任でご利用ください。 また、これらの仕様は予告なく変更する場合がありますのでご了承ください。

概要

Next Design に標準搭載されている多重度制約やパス制約に加えて、モデルのフィールド値などに基づくユーザー独自の制約を追加できます。

動的制約を組み込むには次の実装が必要です。

  • 動的制約のインタフェースの実装
  • 動的制約の登録処理の実装

動的制約のインタフェースの実装

制約の種類に応じてインタフェースを実装します。

詳細は各 API 仕様をご参照ください。

注記
  • 同じ動的制約のインタフェースを複数実装することが可能です。例えば、ビューごとに異なるモデル関連付け時の可否制約を実現する場合、ビューごとにクラスを定義し、 IModelReferenceProvider を実装します。
  • 同じ種類の動的制約は、登録された順に適用されます。
  • ある動的制約の実装で null を返した場合、次の動的制約が適用されます。次の動的制約がない場合、Next Design 標準の振る舞いが適用されます。

動的制約の登録処理の実装

IExtention を実装したメインクラスの公開メソッドである Activate メソッドに、動的制約の登録処理を実装します。


サンプル:モデル追加とコネクタ接続の制限

モデル編集操作時の動的制約のサンプルとして、モデル追加とコネクタ接続に制限を追加する方法を説明します。 以下では、Visual Studio プロジェクトの新規作成から、実際に動的制約を組み込むところまでを説明します。

全体の流れ

  • Visual Studio プロジェクトの新規作成
  • 動的制約のインタフェースの実装
  • 動的制約の登録処理の実装

公開サンプル

  • 以下の手順で作成されるサンプルのソースコード一式を GitHub で公開しています。

    外部リンク: EditingCapabilitySample

ゴールイメージ

画面キャプチャ or GIFアニメ 画面キャプチャ or GIFアニメ

  • Next Design のサンプルプロジェクトから [先進運転システムソフト開発] プロジェクトを開きます。
  • 作業中(名称に「TBD」を含む)モデルに対して、制約を付与します。
    • 接続先のポート名称に「TBD」が含まれる場合、コネクタ接続を不可にします。

      • [システム論理設計] の [システム機能構造] から [機能構造図] でコネクタ接続する際に、「TBDとは関連付けできません」と表示されます。
    • ユースケースの名称に「TBD」が含まれる場合、追加できるモデルを「シナリオ」のみとし、条件の追加を不可にします。

      • [システム要件開発] の [ユースケース] から [ユースケース図] でユースケースを選択してモデルを追加する際に、「条件:事前条件」と「条件:事後条件」が表示されません。

Visual Studio プロジェクトの新規作成

Visual Studio プロジェクトは次のページを参考に新規作成します。

チュートリアル > モデル一括検証

なお、モデル編集操作時の動的制約の追加では、マニフェストに以下の定義は不要です。

  • UI の拡張ポイント定義(リボンタブ・グループ・ボタン)
  • コマンドの拡張ポイント定義

実装例

manifest.json

{
"name": "DensoCreate.NextDesign.Extensions.EditingCapabilitySample",
"version": "1.0.0",
"publisher": "DENSO CREATE Inc.",
"license": "Next Design 使用許諾契約書に準ずる。Copyright (C) 2021 DENSO CREATE INC. All rights reserved.",

"main": "EditingCapabilitySample.dll", // エントリーポイントとしてビルド結果の DLL ファイル名を指定します。
"lifecycle": "project", // ライフサイクルとしてプロジェクトライフサイクルを指定します。
"baseprofile": "車載システムソフト開発" // 対象プロジェクトの条件としてプロファイル名を指定します。
}

動的制約のインタフェースの実装

動的制約を実現するクラスを追加し、制約の種類に応じて次のインタフェースを実装します。

以下のクラスでインタフェースを実装します。

  • ModelReferenceProvider:エディタモデル関連付け時の可否制約
  • ModelCreationProvider:モデル作成時のエンティティ種類の候補制約

実装例

IModelReferenceProvider を実装し、名称にTBDを含むモデルへの接続を制限します。

ModelReferenceProvider.cs

using System.Linq;
using NextDesign.Core;
using NextDesign.Core.EditingCapabilities;
using NextDesign.Desktop;

namespace EditingCapability
{
/// <summary>
/// モデルの関連付け機能をカスタマイズするプロバイダです
/// </summary>
public class ModelReferenceProvider : IModelReferenceProvider
{
/// <summary>
/// コンテキスト。
/// </summary>
private IContext m_Context;

#region 構築・消滅

/// <summary>
/// コンストラクタ。
/// </summary>
/// <param name="context">コンテキスト</param>
public ModelReferenceProvider(IContext context)
{
m_Context = context;
}

#endregion

/// <summary>
/// モデル参照時の選択候補を取得します
/// </summary>
/// <param name="referableParams">選択候補を決めるためのパラメータ</param>
/// <returns>選択候補の結果</returns>
public ModelReferableResult GetReferences(ModelReferableParams referableParams)
{
var model = referableParams.Model;
var modelMetaClass = model.Metaclass;
var field = referableParams.Field;

// 接続先ポートの候補を絞り込みます
if (!IsPort(modelMetaClass))
{
// ポート以外は判定不要です
return null;
}

if (field.Name != "ToPorts")
{
// 接続先ポート以外は判定不要です
return null;
}

var result = CapabilityResults.Ignore;
var models = Enumerable.Empty<IModel>();

if (IsInputPort(modelMetaClass))
{
// 自身が入力ポートの場合、
// 自身の親(コンポーネント)の子コンポーネントの入力ポートかつ名前にTBDを含まないものを候補にします
result = CapabilityResults.Success;
var metamodels = m_Context.App.Workspace.CurrentProject.Profile.Metamodels;
var subSystems = model.Owner.GetChildren().Where(c => c.Metaclass.IsClassOf(metamodels.GetClass("SubSystem")));
var inputPorts = subSystems.SelectMany(s => s.GetChildren().Where(c => (
IsInputPort(c.Metaclass)
&& (!c.Name.Contains("TBD"))
)));
models = inputPorts;
}
else if (IsOutputPort(modelMetaClass))
{
// 自身が出力ポートの場合、
// 自身の親(コンポーネント)の親(コンポーネント)の子コンポーネント(機能のみ)の入力ポートと
// 自身の親(コンポーネント)の親(コンポーネント)の出力ポートかつ名前にTBDを含まないものを候補にします
result = CapabilityResults.Success;
var metamodels = m_Context.App.Workspace.CurrentProject.Profile.Metamodels;
var subSystems = model.Owner.Owner.GetChildren().Where(c => c.Metaclass.IsClassOf(metamodels.GetClass("SubSystem"))).ToList();
var inputPorts = subSystems.SelectMany(s => s.GetChildren().Where(c => (
IsInputPort(c.Metaclass)
&& (!c.Name.Contains("TBD"))
)));
var outputPorts = model.Owner.Owner.GetChildren().Where(c => (
IsOutputPort(c.Metaclass)
&& (!c.Name.Contains("TBD"))
));
models = inputPorts.Union(outputPorts);
}

var referenceResult = new ModelReferableResult
{
Result = result,
Models = models
};
return referenceResult;
}

/// <summary>
/// モデル関連付け可否を判定します
/// </summary>
/// <param name="relateParams">関連付け可否を決めるためのパラメータ</param>
/// <returns>関連付け可否の結果</returns>
public ModelRelateResult CanRelate(ModelRelateParams relateParams)
{
var model = relateParams.Model;
var opposite = relateParams.OppositeModel;
var modelMetaClass = model.Metaclass;
var oppositeMetaClass = opposite.Metaclass;

if (!IsPort(modelMetaClass) || !IsPort(oppositeMetaClass))
{
// ポート以外はNext Designの標準のままとするためnullを返します
return null;
}

var result = CapabilityResults.Ignore;
var canRelate = false;
string guideText = null;
// 「TBD」を名称に含むポートとは接続を制限します。
if (opposite.Name.Contains("TBD"))
{
result = CapabilityResults.Success;
canRelate = false;
guideText = "TBDとは関連付けできません";
}
else
{
// TBD以外はNext Design標準の可否判定のままするためnullを返します。
return null;
}
var relateResult = new ModelRelateResult
{
Result = result,
CanRelate = canRelate,
GuideText = guideText
};

return relateResult;
}

/// <summary>
/// 対象のクラスがポートか判定します
/// </summary>
/// <param name="targetClass">対象のクラス</param>
/// <returns>ポートの場合は真</returns>
private bool IsPort(IClass targetClass)
{
var metamodels = m_Context.App.Workspace.CurrentProject.Profile.Metamodels;
IClass systemStructurePortBase = metamodels.GetClass("SystemStructurePortBase");

return targetClass.IsClassOf(systemStructurePortBase);
}

/// <summary>
/// 対象のクラスが入力ポートか判定します
/// </summary>
/// <param name="targetClass">対象のクラス</param>
/// <returns>ポートの場合は真</returns>
private bool IsInputPort(IClass targetClass)
{
var metamodels = m_Context.App.Workspace.CurrentProject.Profile.Metamodels;
IClass inputPort = metamodels.GetClass("FuntionFlowInputPortInnerSystem");

return targetClass.IsClassOf(inputPort);
}

/// <summary>
/// 対象のクラスが出力ポートか判定します
/// </summary>
/// <param name="targetClass">対象のクラス</param>
/// <returns>ポートの場合は真</returns>
private bool IsOutputPort(IClass targetClass)
{
var metamodels = m_Context.App.Workspace.CurrentProject.Profile.Metamodels;
IClass outputPort = metamodels.GetClass("FuntionFlowOutputPortInnerSystem");

return targetClass.IsClassOf(outputPort);
}
}
}

IModelCreationProvider を実装し、名称にTBDを含むユースケースに追加するモデルを制限します。

ModelCreationProvider.cs

using System;
using System.Collections.Generic;
using System.Text;
using NextDesign.Core;
using NextDesign.Core.EditingCapabilities;
using NextDesign.Desktop;
using System.Linq;

namespace EditingCapability
{
class ModelCreationProvider : IModelCreationProvider
{
public ModelCreatableResult GetCreatableClasses(ModelCreatableParams creatableParams)
{
// ユースケース以外は対象外のためnullを返し、Next Design標準に任せます
var metaClass = creatableParams.Owner.Metaclass;
var metamodels = creatableParams.Project.Profile.Metamodels;
IClass requirementClass = metamodels.GetClass("UseCase");
if (requirementClass != null)
{
if (!metaClass.IsClassOf(requirementClass))
{
return null;
}
}
// 名称に「TBD」がないユースケースは特に制約をかけないためnullを返します
if (!creatableParams.Owner.Name.Contains("TBD"))
{
return null;
}

// 名称に「TBD」があるユースケースは、条件不要で、シナリオのみ作成するルールにします
var creatableResult = new ModelCreatableResult
{
Result = CapabilityResults.Success
};

// DefaultTypesにデフォルトの表示候補があるため、この中から必要なもののみを戻り値に詰めます
foreach (var type in creatableParams.DefaultTypes)
{
// 条件は作成不要のため、それ以外のみをAddします
if (!type.Value.First().Name.Contains("Condition"))
{
creatableResult.AddCreatableClasses(type.Key.Name, type.Value);
}
}

return creatableResult;
}
}
}

動的制約の登録処理の実装

IExtention を実装したメインクラスの公開メソッドである Activate メソッドに動的制約の登録処理を実装します。メインクラスの公開メソッド Deactviate での登録解除処理は不要です。

実装例

モデル追加とコネクタ接続の登録を実装します。

EditingCapabilityEntryPoint.cs

using NextDesign.Core;
using NextDesign.Desktop;
using NextDesign.Extension;

namespace EditingCapability
{
/// <summary>
/// モデル編集操作時の動的制約のエクステンションエントリポイントです
/// </summary>
public class EditingCapabilityEntryPoint : IExtension
{
/// <summary>
/// エクステンションを活性化します
/// </summary>
/// <param name="context">実行コンテキスト</param>
public void Activate(IContext context)
{
// 動的制約を登録します。
var registry = context.App.Workspace.CurrentProject.EditingCapabilityProviderRegistry;
registry.Register(new ModelReferenceProvider(context));
registry.Register(new ModelCreationProvider());
}

/// <summary>
/// エクステンションを非活性化します
/// </summary>
/// <param name="context">実行コンテキスト</param>
public void Deactivate(IContext context)
{
// 制約の解除は不要です。
}
}
}