# **在`aubo_scope`中集成`aubo_caps`的原理**

`aubo_caps`是一个软件包，作为`aubo_scope`的子进程运行。`aubo_scope`将注册`aubo_caps`,并以各种方式与之交互，例如在`aubo_scope`启动的过程中以及基于用户与`aubo_scope`的交互过程中。

每个`aubo_caps`可以为`aubo_scope`贡献多个新功能，这种功能通常称为服务。这种服务一般有以下2类：

**服务**:

> 1. 提供安装节点服务。
> 2. 提供程序节点服务。

**示例**(抓手`aubo_caps`):

> 1. 提供安装节点服务：例如配置抓手的安装和连接。
> 2. 提供程序节点服务：例如一个程序节点可以打开抓手，另一个程序节点可以关闭抓手。

## **将`aubo_caps`集成到`aubo_scope`的原理**概述：

**集成过程图如下**：

> <img src="pics/sample_capsLinkscope.png" style="float:left;" />
>
> - 当`aubo_scope`启动时，它将查找所有已安装的`aubo_caps`。
>
> - 然后`aubo_scope`在每个`aubo_caps`调用激活器，激活器有两个重写的函数`start()`、`stop()`，在启动时首先调用`start()`利用`RegisterService`注册服务；而在`aubo_scope`停止时调用`stop()`函数。
> - 注册后该`Service`提供了配置节点基本信息的函数、创建该节点的用户交互界面（`view`类）的函数以及创建每个节点的`Contribution`类的函数。
> - 在`contribution`类中可以为该节点提供特殊功能的`Api`以及生成相应的`Script`代码。
> - 通常`Service`中的设置可以认为是静态的设置，因为它们不可用于运动时，只在启动时调用。

## **在`aubo_scope`中集成`aubo_caps`程序节点的原理：**

**集成过程图如下：**

> <img src="pics/sample_programlinkscope.png" style="float:left;" />

**具体实现：**

**`ProgramNodeService`**

`ProgramNodeService`接口必须实现以下函数：

> **`getId()`**
>
> 参数：`void`
>
> 返回值类型： `String`
>
> 返回值内容：”`myNodeType`“
>
> 调用时机： 服务注册后。
>
> 说明： `getId()`函数返回此类节点的唯一ID。 当存在多个程序节点时，该函数用于标识哪些程序节点属于同一类程序节点。

------

> **`getTitle()`**
>
> 参数： `Locale`区域
>
> 返回值类型：`String`
>
> 返回值内容： 程序节点的名称。
>
> 调用时机： 服务注册后。
>
> 说明： 它是一个静态名称，应该能够告诉用户该节点的用途。

------

> **`getIcon()`**
>
> 参数：`void`
>
> 返回值类型： `String`
>
> 返回值内容： 返回节点的图标地址。
>
> 调用时机： 服务注册后。
>
> 说明： 由于每一类的节点其图标都各不相同，在动态创建节点的过程中，需要为其匹配相对应的图标，因此我们需要在创建节点时拿到这类节点的图标链接地址。

------

> **`configureContribution()`**
>
> 参数： `ProgramContributionConfigurationPtr `   configuration
>
> 返回值类型: `void`
>
> 调用时机： 服务注册后。
>
> 说明： 
>
> - `ProgramContributionConfigurationPtr`代表此类节点的配置；
>
> - `ProgramContributionConfigurationPtr`对象可以通过调用相关联的函数来配置其值；
>
> - 例如设置程序节点是否可以有子节点、节点是否可以为用户插入还是仅仅在aubo_caps内部使用。
>
>   ```
>   configuration.setChildrenAllowed( false );
>   configuration.setUserInsertable( false );
>   ```

------

> **`createView()`**
>
> 参数： `ViewApiProviderPtr`   api_provider
>
> 返回值类型: `ProgramNodeViewPtr`
>
> 返回值内容： 返回`view`类的新实例。
>
> 调用时机： 仅一次，此类型的节点由用户第一次插入或者加载到程序中。
>
> 说明： 
>
> - 仅在用户首次使用该类节点时才调用`createView`。
> - 参数`ViewApiProviderPtr`对象可以获取 `SystemAPI`、`UserInterfaceAPI`。
> - 参数`ViewApiProviderPtr`通常会被转发到`view`类，例如需要在文本域中提供键盘，而键盘由`UserInterfaceAPI`提供。

------

> **`createNode()`**
>
> 参数： 
>
> - `ProgramApiProviderPtr` api_provider,
> -  `ProgramNodeViewPtr` view，
> - `DataModelPtr` model,
> - `ProgramCreationContextPtr` context                                          
>
> 返回值类型： `ProgramNodeContributionPtr`
>
> 返回值内容：
>
> - 此类节点`contribution`类的新实例;
> - MyProgramNodeContribution（apiProvider, view,  model, context）。
>
> 调用时机： 
>
> - 每当创建此类型的节点时;
> - 要么由用户插入新的节点，然后加载包含此类型节点的程序；
> - 要么由另一个`aubo_caps`插入该程序。
>
> 说明：
>
> - `createNode`返回此类节点`contribution`类的新实例。虽然只有一个`view`实例，但是每次创建一个新节点时，都会创建一个`contribution`类的新实例；
> - 应该将参数转发给`contribution`类。`ProgramApiProviderPtr`可以提供与程序节点相关的各类API的访问权限、`contribution`对象可以使用`DataModelPtr` 存储用户完成的节点的配置信息，如果新插入节点，则`DataModelPtr`将为空；如果加载了该节点，则`DataModelPtr`已经包含用户对该节点的配置信息、`contribution`对象可以使用`ProgramCreationContextPtr`来检查自身的创建是否是新插入节点的结果，或者该节点是否已经被加载。

**`ProgramNodeview`**

`ProgramNodeview`接口必须实现以下函数：

> **`buildUi()`**
>
> 参数： 
>
> - `WidgetHandle` parent,
> - `ContributionProviderPtr`<ProgramNodeContribution> contribution
>
> 返回值类型： `void`
>
> 调用时机：仅一次，当用户第一次插入或者加载这种类型节点到程序中。
>
> 说明：
>
> - `widgetHandle`是`aubo_scope`中显示给用户的面板，在调用`buildUi`期间，我们将节点的界面嵌套在`aubo_scope`面板中；
> - 另一个参数是`ContributionProviderPtr`。由于可以有多个`Contribution`实例，但是只有一个`view`实例，因此当用户与节点交互时`ContributionProviderPtr`将提供对`Contribution`的访问。调用 contribution.get() 将返回活动的`ProgramNodeContribution`实例。

**`ProgramNodecontribution`**

`ProgramNodecontribution`接口必须实现以下函数：

> **`openView()`**
>
> 参数： void
>
> 返回值类型： void
>
> 调用时机： 每次用户进入特定的节点界面时。
>
> 说明： 
>
> - 由于同一种类型的节点其用户界面`view`只有一个实例，但是这种类型的节点可能有多个，其`ProgramNodeContribution`可能也有多个实例，因此应该调用`openView()`函数来更新`view`以显示各个节点的特定设置；
> - 通常，此调用会读取`dataModel`中的设置，这些设置可用于动态更新`Ui`中的相关设置。在这个函数中也可以用来启动一个定时器，只要节点在焦点中，就可以实现动态的更新`Ui`中的值。

------

> **`closeView()`**
>
> 参数： void
>
> 返回值类型： void
>
> 调用时机： 用户每次离开此特定节点的用户界面时。
>
> 说明： 对`closeView()`的调用会通知`Contribution`告知用户现在不再查看此节点。如果在`openView()`中启动了定时器或其他正在运行的任务，那么现在应该停止。

------

> **`getTitle()`**
>
> 参数： void
>
> 返回值类型： String
>
> 返回值内容： 返回程序树中所示的程序节点的名称。
>
> 调用时机： 调用频繁，通常在更改`dataModel`时。
>
> 说明： 
>
> - `Contribution`中getTitle()和`Service`中的getTitle()的区别：`Contribution`中getTitle()函数返回的时程序树中所示的程序节点的名称，是用来区分同一类型的不同节点的；`Service`中的getTitle()函数返回的是可用节点列表中节点的基本名称，是一个静态名称，是用来区别哪些节点是同一类型的。由此也说明了程序树中的节点的名称，通常根据节点的配置而发生变化。
> - 通常，此调用将基于当前配置来更改节点的名称。它用于简化用户在程序树中的导航。例如，如果这是可设置特定夹持宽度的自适应手爪的程序节点，则在设置为35 mm的夹持宽度时，它能会返回**“Gripper Move: 35 mm”**。这有助于用户找到要配置的适当节点。如果未设置夹持宽度，即未定义节点，则标题可能只是“ Gripper Move”。

------

> **`isDefined()`**
>
> 参数： void
>
> 返回值类型： bool
>
> 返回值内容： 目前的节点配置能否生成脚本，如果缺少用于生成`Script`的数据，返回false,反之返回true。
>
> 调用时机： 每当程序中任何地方发生任何的修改时。
>
> 说明： 
>
> - 几乎在程序中的任何地方发生任何修改时，都会调用`isDefined()`.这意味着即使此节点不在焦点上，`isDefined()`也会被调用很多次，这就要求在回调中执行的代码必须非常精简，并且依赖于`dataModel`的值。
> - 此函数的作用不是发出是否已经连接外部硬件的信号，这应该在运行时来处理。`isDefined()`仅用于提醒用户是否需要对此节点进行更多的配置。

------

> **`generateScript()`**
>
> 参数： `ScriptWriterPtr` script_writer
>
> 返回值类型：void
>
> 调用时机： 通常在启动或者保存程序时。
>
> 说明：
>
> - 程序节点和安装节点的目的是生成一些`LuaScript`，这些脚本将在运行程序时被执行。而**`generateScript()`**函数就是为这些节点生成相应的脚本的，生成的脚本取决于`dataModel`中的配置或者创建节点时`service`中设置的静态配置。
> - 该脚本应使用`ScriptWriter`对象创建。

## **在`aubo_scope`中集成`aubo_caps`安装节点的原理：**

**集成过程图如下：**

> <img src="pics/sample_installationlinkscope.png" style="float:left; zoom:80%;" />

**具体实现：**

**`InstallationNodeService`**

`InstallationNodeService`接口必须实现以下函数：

> **`getTitle()`**
>
> 参数： Locale区域
>
> 返回值类型： String
>
> 返回值内容： 返回该安装节点的一个静态名称，能够提示用户该节点的用途。
>
> 说明： 系统Locale作为参数，可用于返回本地化为系统语言的节点名称。

------

> **`getIcon()`**
>
> 参数：`void`
>
> 返回值类型： `String`
>
> 返回值内容： 返回节点的图标地址。
>
> 调用时机： 服务注册后。
>
> 说明： 由于每一类的节点其图标都各不相同，在动态创建节点的过程中，需要为其匹配相对应的图标，因此我们需要在创建节点时拿到这类节点的图标链接地址。

------

> **`configureContribution()`**
>
> 参数：` InstallationContributionConfigurationPtr` configuration
>
> 返回值类型： void
>
> 调用时机： 服务注册后。
>
> 说明： ` InstallationContributionConfigurationPtr`对象存储着这类节点的配置，它已实现供将来使用，目前不提供任何选项，它应该留为空白。

------

> **`createView()`**
>
> 参数： `ViewApiProviderPtr`   api_provider
>
> 返回值类型: `InstallationNodeViewPtr`
>
> 返回值内容： 返回`view`类的新实例。
>
> 调用时机： 仅一次，此类型的节点由用户第一次插入或者加载到程序中。
>
> 说明： 
>
> - 仅在用户首次使用该类节点时才调用`createView`。
> - 参数`ViewApiProviderPtr`对象可以获取 `SystemAPI`、`UserInterfaceAPI`。
> - 参数`ViewApiProviderPtr`通常会被转发到`view`类，例如需要在文本域中提供键盘，而键盘由`UserInterfaceAPI`提供。

------

> **`createNode()`**
>
> 参数： 
>
> - `InstallationApiProviderPtr` api_provider,
> - `InstallationNodeViewPtr` view，
> - `DataModelPtr` model,
> - `InstallationCreationContextPtr` context                                          
>
> 返回值类型： `InstallationNodeContributionPtr`
>
> 返回值内容：
>
> - 此类节点`contribution`类的新实例;
> - MyInstallationNodeContribution（apiProvider, view,  model, context）。
>
> 调用时机： 
>
> - 每当创建此类型的节点时;
> - 要么由用户插入新的节点，然后加载包含此类型节点的程序；
> - 要么由另一个`aubo_caps`插入该程序。
>
> 说明：
>
> - `createNode`返回此类节点`contribution`类的新实例。虽然只有一个`view`实例，但是每次创建一个新节点时，都会创建一个`contribution`类的新实例；
> - 应该将参数转发给`contribution`类。`ProgramApiProviderPtr`可以提供与程序节点相关的各类API的访问权限、`contribution`对象可以使用`DataModelPtr` 存储用户完成的节点的配置信息，如果新插入节点，则`DataModelPtr`将为空；如果加载了该节点(例如作为安装文件的一部分)，则`DataModelPtr`已经包含用户对该节点的配置信息、`contribution`对象可以使用`ProgramCreationContextPtr`来检查自身的创建是否是新插入节点的结果，或者该节点是否已经被加载。

**`InstallationNodeview`**

`InstallationNodeview`接口必须实现以下函数：

> **`buildUi()`**
>
> 参数： 
>
> - `WidgetHandle` parent,
> - `InstallationcontributionNode ContributionPtr` contribution
>
> 返回值类型： `void`
>
> 调用时机：仅一次，当用户第一次插入或者加载这种类型节点到程序中。
>
> 说明：
>
> - `widgetHandle`是`aubo_scope`中显示给用户的面板，在调用`buildUi`期间，我们将节点的界面嵌套在`aubo_scope`面板中；
> - 另一个参数是`ContributionProviderPtr`。由于可以有多个`Contribution`实例，但是只有一个`view`实例，因此当用户与节点交互时`ContributionProviderPtr`将提供对`Contribution`的访问。调用 contribution.get() 将返回活动的`ProgramNodeContribution`实例。

**`InstallationNodecontribution`**

`InstallationNodecontribution`接口必须实现以下函数：

> **`openView()`**
>
> 参数： void
>
> 返回值类型： void
>
> 调用时机： 每次用户进入特定的节点界面时。
>
> 说明： 
>
> - 由于同一种类型的节点其用户界面`view`只有一个实例，但是这种类型的节点可能有多个，其`InstallationNodeContribution`可能也有多个实例，因此应该调用`openView()`函数来更新`view`以显示各个节点的特定设置；
> - 通常，此调用会读取`dataModel`中的设置，这些设置可用于动态更新`Ui`中的相关设置。在这个函数中也可以用来启动一个定时器，只要节点在焦点中，就可以实现动态的更新`Ui`中的值。

------

> **`closeView()`**
>
> 参数： void
>
> 返回值类型： void
>
> 调用时机： 用户每次离开此特定节点的用户界面时。
>
> 说明： 对`closeView()`的调用会通知`Contribution`告知用户现在不再查看此节点。如果在`openView()`中启动了定时器或其他正在运行的任务，那么现在应该停止。

------

> **`generateScript()`**
>
> 参数： `ScriptWriterPtr` script_writer
>
> 返回值类型：void
>
> 调用时机： 通常在启动或者保存程序时。
>
> 说明：程序节点和安装节点的目的是生成一些`Script`，这些脚本将在运行程序时被执行。而**`generateScript()`**函数就是为这些节点生成相应的lua脚本的，生成的脚本取决于`dataModel`中的配置或者创建节点时`service`中设置的静态配置。

