@@ -0,0 +1,51 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
import org.opentcs.customizations.kernel.KernelInjectionModule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Configures/binds the loopback communication adapters of the openTCS kernel.
|
||||
*/
|
||||
public class LoopbackCommAdapterModule
|
||||
extends
|
||||
KernelInjectionModule {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommAdapterModule.class);
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public LoopbackCommAdapterModule() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
VirtualVehicleConfiguration configuration
|
||||
= getConfigBindingProvider().get(
|
||||
VirtualVehicleConfiguration.PREFIX,
|
||||
VirtualVehicleConfiguration.class
|
||||
);
|
||||
|
||||
if (!configuration.enable()) {
|
||||
LOG.info("Loopback driver disabled by configuration.");
|
||||
return;
|
||||
}
|
||||
|
||||
bind(VirtualVehicleConfiguration.class)
|
||||
.toInstance(configuration);
|
||||
|
||||
install(new FactoryModuleBuilder().build(LoopbackAdapterComponentsFactory.class));
|
||||
|
||||
// tag::documentation_createCommAdapterModule[]
|
||||
vehicleCommAdaptersBinder().addBinding().to(LoopbackCommunicationAdapterFactory.class);
|
||||
// end::documentation_createCommAdapterModule[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-FileCopyrightText: The openTCS Authors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
org.opentcs.virtualvehicle.LoopbackCommAdapterModule
|
||||
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import org.opentcs.components.kernel.services.VehicleService;
|
||||
|
||||
/**
|
||||
* A factory for creating various comm adapter panel specific instances.
|
||||
*/
|
||||
public interface AdapterPanelComponentsFactory {
|
||||
|
||||
/**
|
||||
* Creates a {@link LoopbackCommAdapterPanel} representing the given process model's content.
|
||||
*
|
||||
* @param processModel The process model to represent.
|
||||
* @param vehicleService The vehicle service used for interaction with the comm adapter.
|
||||
* @return The comm adapter panel.
|
||||
*/
|
||||
LoopbackCommAdapterPanel createPanel(
|
||||
LoopbackVehicleModelTO processModel,
|
||||
VehicleService vehicleService
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
/**
|
||||
* Defines constants regarding internationalization.
|
||||
*/
|
||||
public interface I18nLoopbackCommAdapter {
|
||||
|
||||
/**
|
||||
* The path to the project's resource bundle.
|
||||
*/
|
||||
String BUNDLE_PATH = "i18n/org/opentcs/commadapter/loopback/Bundle";
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
|
||||
/**
|
||||
* A factory for various loopback specific instances.
|
||||
*/
|
||||
public interface LoopbackAdapterComponentsFactory {
|
||||
|
||||
/**
|
||||
* Creates a new LoopbackCommunicationAdapter for the given vehicle.
|
||||
*
|
||||
* @param vehicle The vehicle.
|
||||
* @return A new LoopbackCommunicationAdapter for the given vehicle.
|
||||
*/
|
||||
LoopbackCommunicationAdapter createLoopbackCommAdapter(Vehicle vehicle);
|
||||
}
|
||||
@@ -0,0 +1,961 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Component class="javax.swing.ButtonGroup" name="modeButtonGroup">
|
||||
</Component>
|
||||
<Component class="javax.swing.ButtonGroup" name="propertyEditorGroup">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="name" type="java.lang.String" value="LoopbackCommunicationAdapterPanel" noResource="true"/>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.accessibleName" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</AccessibilityProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,118,0,0,3,12"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="vehicleBahaviourPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="PropsPowerOuterContainerPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="North"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="PropsPowerInnerContainerPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="West"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||
<Property name="axis" type="int" value="0"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="vehiclePropsPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Vehicle properties">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_vehicleProperties.border.title" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="maxFwdVeloLbl">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_maximumForwardVelocity.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="maxFwdVeloTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="5"/>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="0"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxFwdVeloUnitLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="mm/s"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxRevVeloLbl">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_maximumReverseVelocity.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="maxRevVeloTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="5"/>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="0"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxRevVeloUnitLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="mm/s"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxAccelLbl">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_maximumAcceleration.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="maxAccelTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="5"/>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="1000"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxAccelUnitLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="<html>mm/s<sup>2</sup>"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="maxDecelTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="5"/>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="1000"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxDecelLbl">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_maximumDeceleration.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxDecelUnitLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="<html>mm/s<sup>2</sup>"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="defaultOpTimeLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_operatingTime.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="defaultOpTimeUntiLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="ms"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="opTimeTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="5"/>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="1000"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="profilesContainerPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="South"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.Box$Filler" name="filler1">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 0]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalGlue"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="vehicleStatePanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="West"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="stateContainerPanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="North"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||
<Property name="axis" type="int" value="1"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="connectionPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Adapter status">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_adapterStatus.border.title" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="connectionPanel" noResource="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="chkBoxEnable">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.checkBox_enableAdapter.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="chkBoxEnable" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkBoxEnableActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="curPosPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Current position/state">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_vehicleStatus.border.title" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="curPosPanel" noResource="true"/>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Change"/>
|
||||
</AccessibilityProperties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextField" name="energyLevelTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="100"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="energyLevelTxt" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="energyLevelTxtMouseClicked"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="energyLevelLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="%"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="pauseVehicleCheckBox">
|
||||
<Properties>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||
<Property name="horizontalTextPosition" type="int" value="10"/>
|
||||
<Property name="name" type="java.lang.String" value="pauseVehicleCheckBox" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="pauseVehicleCheckBoxItemStateChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="orientationAngleLbl">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="<html>&#186;"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="precisePosUnitLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="mm"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="orientationAngleTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.textField_orientationAngle.angleNotSetPlaceholder" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="orientationAngleTxt" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="orientationAngleTxtMouseClicked"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="energyLevelLabel">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_energyLevel.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="orientationLabel">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_orientationAngle.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="positionTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="positionTxt" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="positionTxtMouseClicked"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="positionLabel">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_position.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="pauseVehicleLabel">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_pauseVehicle.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_state.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="stateTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="stateTxt" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="stateTxtMouseClicked"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel3">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="11"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_precisePosition.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextArea" name="precisePosTextArea">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection component="positionTxt" name="getFont" type="method"/>
|
||||
</Property>
|
||||
<Property name="rows" type="int" value="3"/>
|
||||
<Property name="text" type="java.lang.String" value="X:
Y:
Z:"/>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="precisePosTextArea" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="precisePosTextAreaMouseClicked"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="propertySetterPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Vehicle property">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_vehicleProperty.border.title" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="keyLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.label_propertyKey.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="3" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="valueTextField">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[4, 18]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[4, 18]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[100, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="propSetButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.button_setProperty.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="propSetButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="4" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="removePropRadioBtn">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="propertyEditorGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.radioButton_removeProperty.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removePropRadioBtnActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="setPropValueRadioBtn">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="propertyEditorGroup"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.radioButton_setProperty.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="setPropValueRadioBtnActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="jPanel3">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextField" name="keyTextField">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[100, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="eventPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Event dispatching">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_eventDispatching.title" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="includeAppendixCheckBox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.checkBox_includeAppendix.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="includeAppendixCheckBoxItemStateChanged"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="appendixTxt">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="10"/>
|
||||
<Property name="text" type="java.lang.String" value="XYZ"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="dispatchEventButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.button_dispatchEvent.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dispatchEventButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="dispatchCommandFailedButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.button_failCurrentCommand.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dispatchCommandFailedButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="controlTabPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Command processing">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_commandProcessing.border.title" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JRadioButton" name="singleModeRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="modeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.checkBox_commandProcessingManual.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
|
||||
<EmptyBorder bottom="0" left="0" right="0" top="0"/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[0, 0, 0, 0]"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="singleModeRadioButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="singleModeRadioButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JRadioButton" name="flowModeRadioButton">
|
||||
<Properties>
|
||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||
<ComponentRef name="modeButtonGroup"/>
|
||||
</Property>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.checkBox_commandProcessingAutomatic.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
|
||||
<EmptyBorder bottom="0" left="0" right="0" top="0"/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[0, 0, 0, 0]"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="flowModeRadioButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="flowModeRadioButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="triggerButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.button_nextStep.text" replaceFormat="BUNDLE.getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
<Property name="name" type="java.lang.String" value="triggerButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="triggerButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="13" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="loadDevicePanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Load handling device">
|
||||
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="loopbackCommAdapterPanel.panel_loadHandlingDevice.border.title" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="South"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jPanel2">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="West"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JCheckBox" name="lHDCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Device loaded"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="lHDCheckboxClicked"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,126 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.opentcs.access.KernelServicePortal;
|
||||
import org.opentcs.data.TCSObjectReference;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleCommAdapterPanel;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleCommAdapterPanelFactory;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A factory for creating {@link LoopbackCommAdapterPanel} instances.
|
||||
*/
|
||||
public class LoopbackCommAdapterPanelFactory
|
||||
implements
|
||||
VehicleCommAdapterPanelFactory {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommAdapterPanelFactory.class);
|
||||
/**
|
||||
* The service portal.
|
||||
*/
|
||||
private final KernelServicePortal servicePortal;
|
||||
/**
|
||||
* The components factory.
|
||||
*/
|
||||
private final AdapterPanelComponentsFactory componentsFactory;
|
||||
/**
|
||||
* Whether this factory is initialized or not.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param servicePortal The service portal.
|
||||
* @param componentsFactory The components factory.
|
||||
*/
|
||||
@Inject
|
||||
public LoopbackCommAdapterPanelFactory(
|
||||
KernelServicePortal servicePortal,
|
||||
AdapterPanelComponentsFactory componentsFactory
|
||||
) {
|
||||
this.servicePortal = requireNonNull(servicePortal, "servicePortal");
|
||||
this.componentsFactory = requireNonNull(componentsFactory, "componentsFactory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VehicleCommAdapterPanel> getPanelsFor(
|
||||
@Nonnull
|
||||
VehicleCommAdapterDescription description,
|
||||
@Nonnull
|
||||
TCSObjectReference<Vehicle> vehicle,
|
||||
@Nonnull
|
||||
VehicleProcessModelTO processModel
|
||||
) {
|
||||
requireNonNull(description, "description");
|
||||
requireNonNull(vehicle, "vehicle");
|
||||
requireNonNull(processModel, "processModel");
|
||||
|
||||
if (!providesPanelsFor(description, processModel)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<VehicleCommAdapterPanel> panels = new ArrayList<>();
|
||||
panels.add(
|
||||
componentsFactory.createPanel(
|
||||
((LoopbackVehicleModelTO) processModel),
|
||||
servicePortal.getVehicleService()
|
||||
)
|
||||
);
|
||||
return panels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this factory can provide comm adapter panels for the given description and the
|
||||
* given type of process model.
|
||||
*
|
||||
* @param description The description to check for.
|
||||
* @param processModel The process model.
|
||||
* @return {@code true} if, and only if, this factory can provide comm adapter panels for the
|
||||
* given description and the given type of process model.
|
||||
*/
|
||||
private boolean providesPanelsFor(
|
||||
VehicleCommAdapterDescription description,
|
||||
VehicleProcessModelTO processModel
|
||||
) {
|
||||
return (description instanceof LoopbackCommunicationAdapterDescription)
|
||||
&& (processModel instanceof LoopbackVehicleModelTO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,559 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import jakarta.inject.Inject;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import org.opentcs.common.LoopbackAdapterConstants;
|
||||
import org.opentcs.customizations.kernel.KernelExecutor;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.data.order.Route.Step;
|
||||
import org.opentcs.data.order.TransportOrder;
|
||||
import org.opentcs.drivers.vehicle.BasicVehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.LoadHandlingDevice;
|
||||
import org.opentcs.drivers.vehicle.MovementCommand;
|
||||
import org.opentcs.drivers.vehicle.SimVehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.VehicleProcessModel;
|
||||
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
|
||||
import org.opentcs.util.ExplainedBoolean;
|
||||
import org.opentcs.virtualvehicle.VelocityController.WayEntry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A {@link VehicleCommAdapter} that does not really communicate with a physical vehicle but roughly
|
||||
* simulates one.
|
||||
*/
|
||||
public class LoopbackCommunicationAdapter
|
||||
extends
|
||||
BasicVehicleCommAdapter
|
||||
implements
|
||||
SimVehicleCommAdapter {
|
||||
|
||||
/**
|
||||
* The name of the load handling device set by this adapter.
|
||||
*/
|
||||
public static final String LHD_NAME = "default";
|
||||
/**
|
||||
* This class's Logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommunicationAdapter.class);
|
||||
/**
|
||||
* An error code indicating that there's a conflict between a load operation and the vehicle's
|
||||
* current load state.
|
||||
*/
|
||||
private static final String LOAD_OPERATION_CONFLICT = "cannotLoadWhenLoaded";
|
||||
/**
|
||||
* An error code indicating that there's a conflict between an unload operation and the vehicle's
|
||||
* current load state.
|
||||
*/
|
||||
private static final String UNLOAD_OPERATION_CONFLICT = "cannotUnloadWhenNotLoaded";
|
||||
/**
|
||||
* The time (in ms) of a single simulation step.
|
||||
*/
|
||||
private static final int SIMULATION_PERIOD = 100;
|
||||
/**
|
||||
* This instance's configuration.
|
||||
*/
|
||||
private final VirtualVehicleConfiguration configuration;
|
||||
/**
|
||||
* Indicates whether the vehicle simulation is running or not.
|
||||
*/
|
||||
private volatile boolean isSimulationRunning;
|
||||
/**
|
||||
* The vehicle to this comm adapter instance.
|
||||
*/
|
||||
private final Vehicle vehicle;
|
||||
/**
|
||||
* The vehicle's load state.
|
||||
*/
|
||||
private LoadState loadState = LoadState.EMPTY;
|
||||
/**
|
||||
* Whether the loopback adapter is initialized or not.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param configuration This class's configuration.
|
||||
* @param vehicle The vehicle this adapter is associated with.
|
||||
* @param kernelExecutor The kernel's executor.
|
||||
*/
|
||||
@Inject
|
||||
public LoopbackCommunicationAdapter(
|
||||
VirtualVehicleConfiguration configuration,
|
||||
@Assisted
|
||||
Vehicle vehicle,
|
||||
@KernelExecutor
|
||||
ScheduledExecutorService kernelExecutor
|
||||
) {
|
||||
super(
|
||||
new LoopbackVehicleModel(vehicle),
|
||||
configuration.commandQueueCapacity(),
|
||||
configuration.rechargeOperation(),
|
||||
kernelExecutor
|
||||
);
|
||||
this.vehicle = requireNonNull(vehicle, "vehicle");
|
||||
this.configuration = requireNonNull(configuration, "configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
super.initialize();
|
||||
|
||||
String initialPos
|
||||
= vehicle.getProperties().get(LoopbackAdapterConstants.PROPKEY_INITIAL_POSITION);
|
||||
if (initialPos != null) {
|
||||
initVehiclePosition(initialPos);
|
||||
}
|
||||
getProcessModel().setState(Vehicle.State.IDLE);
|
||||
getProcessModel().setLoadHandlingDevices(
|
||||
Arrays.asList(new LoadHandlingDevice(LHD_NAME, false))
|
||||
);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
super.terminate();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
super.propertyChange(evt);
|
||||
|
||||
if (!((evt.getSource()) instanceof LoopbackVehicleModel)) {
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(
|
||||
evt.getPropertyName(),
|
||||
VehicleProcessModel.Attribute.LOAD_HANDLING_DEVICES.name()
|
||||
)) {
|
||||
if (!getProcessModel().getLoadHandlingDevices().isEmpty()
|
||||
&& getProcessModel().getLoadHandlingDevices().get(0).isFull()) {
|
||||
loadState = LoadState.FULL;
|
||||
getProcessModel().setBoundingBox(
|
||||
getProcessModel().getBoundingBox().withLength(configuration.vehicleLengthLoaded())
|
||||
);
|
||||
}
|
||||
else {
|
||||
loadState = LoadState.EMPTY;
|
||||
getProcessModel().setBoundingBox(
|
||||
getProcessModel().getBoundingBox().withLength(configuration.vehicleLengthUnloaded())
|
||||
);
|
||||
}
|
||||
}
|
||||
if (Objects.equals(
|
||||
evt.getPropertyName(),
|
||||
LoopbackVehicleModel.Attribute.SINGLE_STEP_MODE.name()
|
||||
)) {
|
||||
// When switching from single step mode to automatic mode and there are commands to be
|
||||
// processed, ensure that we start/continue processing them.
|
||||
if (!getProcessModel().isSingleStepModeEnabled()
|
||||
&& !getSentCommands().isEmpty()
|
||||
&& !isSimulationRunning) {
|
||||
isSimulationRunning = true;
|
||||
((ExecutorService) getExecutor()).submit(
|
||||
() -> startVehicleSimulation(getSentCommands().peek())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void enable() {
|
||||
if (isEnabled()) {
|
||||
return;
|
||||
}
|
||||
super.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void disable() {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
super.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoopbackVehicleModel getProcessModel() {
|
||||
return (LoopbackVehicleModel) super.getProcessModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void sendCommand(MovementCommand cmd) {
|
||||
requireNonNull(cmd, "cmd");
|
||||
|
||||
// Start the simulation task if we're not in single step mode and not simulating already.
|
||||
if (!getProcessModel().isSingleStepModeEnabled()
|
||||
&& !isSimulationRunning) {
|
||||
isSimulationRunning = true;
|
||||
// The command is added to the sent queue after this method returns. Therefore
|
||||
// we have to explicitly start the simulation like this.
|
||||
if (getSentCommands().isEmpty()) {
|
||||
((ExecutorService) getExecutor()).submit(() -> startVehicleSimulation(cmd));
|
||||
}
|
||||
else {
|
||||
((ExecutorService) getExecutor()).submit(
|
||||
() -> startVehicleSimulation(getSentCommands().peek())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVehiclePaused(boolean paused) {
|
||||
getProcessModel().setVehiclePaused(paused);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processMessage(Object message) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void initVehiclePosition(String newPos) {
|
||||
((ExecutorService) getExecutor()).submit(() -> getProcessModel().setPosition(newPos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ExplainedBoolean canProcess(TransportOrder order) {
|
||||
requireNonNull(order, "order");
|
||||
|
||||
return canProcess(
|
||||
order.getFutureDriveOrders().stream()
|
||||
.map(driveOrder -> driveOrder.getDestination().getOperation())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
private ExplainedBoolean canProcess(List<String> operations) {
|
||||
requireNonNull(operations, "operations");
|
||||
|
||||
LOG.debug("{}: Checking processability of {}...", getName(), operations);
|
||||
boolean canProcess = true;
|
||||
String reason = "";
|
||||
|
||||
// Do NOT require the vehicle to be IDLE or CHARGING here!
|
||||
// That would mean a vehicle moving to a parking position or recharging location would always
|
||||
// have to finish that order first, which would render a transport order's dispensable flag
|
||||
// useless.
|
||||
boolean loaded = loadState == LoadState.FULL;
|
||||
Iterator<String> opIter = operations.iterator();
|
||||
while (canProcess && opIter.hasNext()) {
|
||||
final String nextOp = opIter.next();
|
||||
// If we're loaded, we cannot load another piece, but could unload.
|
||||
if (loaded) {
|
||||
if (nextOp.startsWith(getProcessModel().getLoadOperation())) {
|
||||
canProcess = false;
|
||||
reason = LOAD_OPERATION_CONFLICT;
|
||||
}
|
||||
else if (nextOp.startsWith(getProcessModel().getUnloadOperation())) {
|
||||
loaded = false;
|
||||
}
|
||||
} // If we're not loaded, we could load, but not unload.
|
||||
else if (nextOp.startsWith(getProcessModel().getLoadOperation())) {
|
||||
loaded = true;
|
||||
}
|
||||
else if (nextOp.startsWith(getProcessModel().getUnloadOperation())) {
|
||||
canProcess = false;
|
||||
reason = UNLOAD_OPERATION_CONFLICT;
|
||||
}
|
||||
}
|
||||
if (!canProcess) {
|
||||
LOG.debug("{}: Cannot process {}, reason: '{}'", getName(), operations, reason);
|
||||
}
|
||||
return new ExplainedBoolean(canProcess, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void connectVehicle() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void disconnectVehicle() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean isVehicleConnected() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VehicleProcessModelTO createCustomTransferableProcessModel() {
|
||||
return new LoopbackVehicleModelTO()
|
||||
.setLoadOperation(getProcessModel().getLoadOperation())
|
||||
.setMaxAcceleration(getProcessModel().getMaxAcceleration())
|
||||
.setMaxDeceleration(getProcessModel().getMaxDecceleration())
|
||||
.setMaxFwdVelocity(getProcessModel().getMaxFwdVelocity())
|
||||
.setMaxRevVelocity(getProcessModel().getMaxRevVelocity())
|
||||
.setOperatingTime(getProcessModel().getOperatingTime())
|
||||
.setSingleStepModeEnabled(getProcessModel().isSingleStepModeEnabled())
|
||||
.setUnloadOperation(getProcessModel().getUnloadOperation())
|
||||
.setVehiclePaused(getProcessModel().isVehiclePaused());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a step in single step mode.
|
||||
*/
|
||||
public synchronized void trigger() {
|
||||
if (getProcessModel().isSingleStepModeEnabled()
|
||||
&& !getSentCommands().isEmpty()
|
||||
&& !isSimulationRunning) {
|
||||
isSimulationRunning = true;
|
||||
((ExecutorService) getExecutor()).submit(
|
||||
() -> startVehicleSimulation(getSentCommands().peek())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void startVehicleSimulation(MovementCommand command) {
|
||||
LOG.debug("Starting vehicle simulation for command: {}", command);
|
||||
Step step = command.getStep();
|
||||
getProcessModel().setState(Vehicle.State.EXECUTING);
|
||||
|
||||
if (step.getPath() == null) {
|
||||
LOG.debug("Starting operation simulation...");
|
||||
getExecutor().schedule(
|
||||
() -> operationSimulation(command, 0),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
getProcessModel().getVelocityController().addWayEntry(
|
||||
new WayEntry(
|
||||
step.getPath().getLength(),
|
||||
maxVelocity(step),
|
||||
step.getDestinationPoint().getName(),
|
||||
step.getVehicleOrientation()
|
||||
)
|
||||
);
|
||||
|
||||
LOG.debug("Starting movement simulation...");
|
||||
getExecutor().schedule(
|
||||
() -> movementSimulation(command),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private int maxVelocity(Step step) {
|
||||
return (step.getVehicleOrientation() == Vehicle.Orientation.BACKWARD)
|
||||
? step.getPath().getMaxReverseVelocity()
|
||||
: step.getPath().getMaxVelocity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate the movement part of a MovementCommand.
|
||||
*
|
||||
* @param command The command to simulate.
|
||||
*/
|
||||
private void movementSimulation(MovementCommand command) {
|
||||
if (!getProcessModel().getVelocityController().hasWayEntries()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WayEntry prevWayEntry = getProcessModel().getVelocityController().getCurrentWayEntry();
|
||||
getProcessModel().getVelocityController().advanceTime(getSimulationTimeStep());
|
||||
WayEntry currentWayEntry = getProcessModel().getVelocityController().getCurrentWayEntry();
|
||||
//if we are still on the same way entry then reschedule to do it again
|
||||
if (prevWayEntry == currentWayEntry) {
|
||||
getExecutor().schedule(
|
||||
() -> movementSimulation(command),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
//if the way enties are different then we have finished this step
|
||||
//and we can move on.
|
||||
getProcessModel().setPosition(prevWayEntry.getDestPointName());
|
||||
LOG.debug("Movement simulation finished.");
|
||||
if (!command.hasEmptyOperation()) {
|
||||
LOG.debug("Starting operation simulation...");
|
||||
getExecutor().schedule(
|
||||
() -> operationSimulation(command, 0),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
finishMovementCommand(command);
|
||||
simulateNextCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate the operation part of a movement command.
|
||||
*
|
||||
* @param command The command to simulate.
|
||||
* @param timePassed The amount of time passed since starting the simulation.
|
||||
*/
|
||||
private void operationSimulation(
|
||||
MovementCommand command,
|
||||
int timePassed
|
||||
) {
|
||||
if (timePassed < getProcessModel().getOperatingTime()) {
|
||||
getProcessModel().getVelocityController().advanceTime(getSimulationTimeStep());
|
||||
getExecutor().schedule(
|
||||
() -> operationSimulation(command, timePassed + getSimulationTimeStep()),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOG.debug("Operation simulation finished.");
|
||||
finishMovementCommand(command);
|
||||
String operation = command.getOperation();
|
||||
if (operation.equals(getProcessModel().getLoadOperation())) {
|
||||
// Update load handling devices as defined by this operation
|
||||
getProcessModel().setLoadHandlingDevices(
|
||||
Arrays.asList(new LoadHandlingDevice(LHD_NAME, true))
|
||||
);
|
||||
simulateNextCommand();
|
||||
}
|
||||
else if (operation.equals(getProcessModel().getUnloadOperation())) {
|
||||
getProcessModel().setLoadHandlingDevices(
|
||||
Arrays.asList(new LoadHandlingDevice(LHD_NAME, false))
|
||||
);
|
||||
simulateNextCommand();
|
||||
}
|
||||
else if (operation.equals(this.getRechargeOperation())) {
|
||||
LOG.debug("Starting recharge simulation...");
|
||||
finishMovementCommand(command);
|
||||
getProcessModel().setState(Vehicle.State.CHARGING);
|
||||
getExecutor().schedule(
|
||||
() -> chargingSimulation(
|
||||
getProcessModel().getPosition(),
|
||||
getProcessModel().getEnergyLevel()
|
||||
),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
simulateNextCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate recharging the vehicle.
|
||||
*
|
||||
* @param rechargePosition The vehicle position where the recharge simulation was started.
|
||||
* @param rechargePercentage The recharge percentage of the vehicle while it is charging.
|
||||
*/
|
||||
private void chargingSimulation(
|
||||
String rechargePosition,
|
||||
float rechargePercentage
|
||||
) {
|
||||
if (!getSentCommands().isEmpty()) {
|
||||
LOG.debug("Aborting recharge operation, vehicle has an order...");
|
||||
simulateNextCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
if (getProcessModel().getState() != Vehicle.State.CHARGING) {
|
||||
LOG.debug("Aborting recharge operation, vehicle no longer charging state...");
|
||||
simulateNextCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Objects.equals(getProcessModel().getPosition(), rechargePosition)) {
|
||||
LOG.debug("Aborting recharge operation, vehicle position changed...");
|
||||
simulateNextCommand();
|
||||
return;
|
||||
}
|
||||
if (nextChargePercentage(rechargePercentage) < 100.0) {
|
||||
getProcessModel().setEnergyLevel((int) rechargePercentage);
|
||||
getExecutor().schedule(
|
||||
() -> chargingSimulation(rechargePosition, nextChargePercentage(rechargePercentage)),
|
||||
SIMULATION_PERIOD,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOG.debug("Finishing recharge operation, vehicle at 100%...");
|
||||
getProcessModel().setEnergyLevel(100);
|
||||
simulateNextCommand();
|
||||
}
|
||||
}
|
||||
|
||||
private float nextChargePercentage(float basePercentage) {
|
||||
return basePercentage
|
||||
+ (float) (configuration.rechargePercentagePerSecond() / 1000.0) * SIMULATION_PERIOD;
|
||||
}
|
||||
|
||||
private void finishMovementCommand(MovementCommand command) {
|
||||
//Set the vehicle state to idle
|
||||
if (getSentCommands().size() <= 1 && getUnsentCommands().isEmpty()) {
|
||||
getProcessModel().setState(Vehicle.State.IDLE);
|
||||
}
|
||||
if (Objects.equals(getSentCommands().peek(), command)) {
|
||||
// Let the comm adapter know we have finished this command.
|
||||
getProcessModel().commandExecuted(getSentCommands().poll());
|
||||
}
|
||||
else {
|
||||
LOG.warn(
|
||||
"{}: Simulated command not oldest in sent queue: {} != {}",
|
||||
getName(),
|
||||
command,
|
||||
getSentCommands().peek()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void simulateNextCommand() {
|
||||
if (getSentCommands().isEmpty() || getProcessModel().isSingleStepModeEnabled()) {
|
||||
LOG.debug("Vehicle simulation is done.");
|
||||
getProcessModel().setState(Vehicle.State.IDLE);
|
||||
isSimulationRunning = false;
|
||||
}
|
||||
else {
|
||||
LOG.debug("Triggering simulation for next command: {}", getSentCommands().peek());
|
||||
((ExecutorService) getExecutor()).submit(
|
||||
() -> startVehicleSimulation(getSentCommands().peek())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private int getSimulationTimeStep() {
|
||||
return (int) (SIMULATION_PERIOD * configuration.simulationTimeFactor());
|
||||
}
|
||||
|
||||
/**
|
||||
* The vehicle's possible load states.
|
||||
*/
|
||||
private enum LoadState {
|
||||
EMPTY,
|
||||
FULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static org.opentcs.virtualvehicle.I18nLoopbackCommAdapter.BUNDLE_PATH;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
|
||||
|
||||
/**
|
||||
* The loopback adapter's {@link VehicleCommAdapterDescription}.
|
||||
*/
|
||||
public class LoopbackCommunicationAdapterDescription
|
||||
extends
|
||||
VehicleCommAdapterDescription {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public LoopbackCommunicationAdapterDescription() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return ResourceBundle.getBundle(BUNDLE_PATH)
|
||||
.getString("loopbackCommunicationAdapterDescription.description");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimVehicleCommAdapter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterDescription;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterFactory;
|
||||
|
||||
/**
|
||||
* A factory for loopback communication adapters (virtual vehicles).
|
||||
*/
|
||||
public class LoopbackCommunicationAdapterFactory
|
||||
implements
|
||||
VehicleCommAdapterFactory {
|
||||
|
||||
/**
|
||||
* The adapter components factory.
|
||||
*/
|
||||
private final LoopbackAdapterComponentsFactory adapterFactory;
|
||||
/**
|
||||
* Indicates whether this component is initialized or not.
|
||||
*/
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Creates a new factory.
|
||||
*
|
||||
* @param componentsFactory The adapter components factory.
|
||||
*/
|
||||
@Inject
|
||||
public LoopbackCommunicationAdapterFactory(LoopbackAdapterComponentsFactory componentsFactory) {
|
||||
this.adapterFactory = requireNonNull(componentsFactory, "componentsFactory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (isInitialized()) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
if (!isInitialized()) {
|
||||
return;
|
||||
}
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VehicleCommAdapterDescription getDescription() {
|
||||
return new LoopbackCommunicationAdapterDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean providesAdapterFor(Vehicle vehicle) {
|
||||
requireNonNull(vehicle, "vehicle");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoopbackCommunicationAdapter getAdapterFor(Vehicle vehicle) {
|
||||
requireNonNull(vehicle, "vehicle");
|
||||
return adapterFactory.createLoopbackCommAdapter(vehicle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.opentcs.common.LoopbackAdapterConstants;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.drivers.vehicle.VehicleProcessModel;
|
||||
|
||||
/**
|
||||
* An observable model of a virtual vehicle's and its comm adapter's attributes.
|
||||
*/
|
||||
public class LoopbackVehicleModel
|
||||
extends
|
||||
VehicleProcessModel {
|
||||
|
||||
/**
|
||||
* Indicates whether this communication adapter is in single step mode or not (i.e. in automatic
|
||||
* mode).
|
||||
*/
|
||||
private boolean singleStepModeEnabled;
|
||||
/**
|
||||
* Indicates which operation is a loading operation.
|
||||
*/
|
||||
private final String loadOperation;
|
||||
/**
|
||||
* Indicates which operation is an unloading operation.
|
||||
*/
|
||||
private final String unloadOperation;
|
||||
/**
|
||||
* The time needed for executing operations.
|
||||
*/
|
||||
private int operatingTime;
|
||||
/**
|
||||
* The velocity controller for calculating the simulated vehicle's velocity and current position.
|
||||
*/
|
||||
private final VelocityController velocityController;
|
||||
|
||||
public LoopbackVehicleModel(Vehicle attachedVehicle) {
|
||||
super(attachedVehicle);
|
||||
this.velocityController = new VelocityController(
|
||||
parseDeceleration(attachedVehicle),
|
||||
parseAcceleration(attachedVehicle),
|
||||
attachedVehicle.getMaxReverseVelocity(),
|
||||
attachedVehicle.getMaxVelocity()
|
||||
);
|
||||
this.operatingTime = parseOperatingTime(attachedVehicle);
|
||||
this.loadOperation = extractLoadOperation(attachedVehicle);
|
||||
this.unloadOperation = extractUnloadOperation(attachedVehicle);
|
||||
}
|
||||
|
||||
public String getLoadOperation() {
|
||||
return this.loadOperation;
|
||||
}
|
||||
|
||||
public String getUnloadOperation() {
|
||||
return this.unloadOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this communication adapter's <em>single step mode</em> flag.
|
||||
*
|
||||
* @param mode If <code>true</code>, sets this adapter to single step mode,
|
||||
* otherwise sets this adapter to flow mode.
|
||||
*/
|
||||
public synchronized void setSingleStepModeEnabled(final boolean mode) {
|
||||
boolean oldValue = singleStepModeEnabled;
|
||||
singleStepModeEnabled = mode;
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.SINGLE_STEP_MODE.name(),
|
||||
oldValue,
|
||||
mode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this communication adapter's <em>single step mode</em> flag.
|
||||
*
|
||||
* @return <code>true</code> if, and only if, this adapter is currently in
|
||||
* single step mode.
|
||||
*/
|
||||
public synchronized boolean isSingleStepModeEnabled() {
|
||||
return singleStepModeEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default operating time.
|
||||
*
|
||||
* @return The default operating time
|
||||
*/
|
||||
public synchronized int getOperatingTime() {
|
||||
return operatingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default operating time.
|
||||
*
|
||||
* @param defaultOperatingTime The new default operating time
|
||||
*/
|
||||
public synchronized void setOperatingTime(int defaultOperatingTime) {
|
||||
int oldValue = this.operatingTime;
|
||||
this.operatingTime = defaultOperatingTime;
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.OPERATING_TIME.name(),
|
||||
oldValue,
|
||||
defaultOperatingTime
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum deceleration.
|
||||
*
|
||||
* @return The maximum deceleration
|
||||
*/
|
||||
public synchronized int getMaxDecceleration() {
|
||||
return velocityController.getMaxDeceleration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum deceleration.
|
||||
*
|
||||
* @param maxDeceleration The new maximum deceleration
|
||||
*/
|
||||
public synchronized void setMaxDeceleration(int maxDeceleration) {
|
||||
int oldValue = velocityController.getMaxDeceleration();
|
||||
velocityController.setMaxDeceleration(maxDeceleration);
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.DECELERATION.name(),
|
||||
oldValue,
|
||||
maxDeceleration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum acceleration.
|
||||
*
|
||||
* @return The maximum acceleration
|
||||
*/
|
||||
public synchronized int getMaxAcceleration() {
|
||||
return velocityController.getMaxAcceleration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum acceleration.
|
||||
*
|
||||
* @param maxAcceleration The new maximum acceleration
|
||||
*/
|
||||
public synchronized void setMaxAcceleration(int maxAcceleration) {
|
||||
int oldValue = velocityController.getMaxAcceleration();
|
||||
velocityController.setMaxAcceleration(maxAcceleration);
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.ACCELERATION.name(),
|
||||
oldValue,
|
||||
maxAcceleration
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum reverse velocity.
|
||||
*
|
||||
* @return The maximum reverse velocity.
|
||||
*/
|
||||
public synchronized int getMaxRevVelocity() {
|
||||
return velocityController.getMaxRevVelocity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum reverse velocity.
|
||||
*
|
||||
* @param maxRevVelocity The new maximum reverse velocity
|
||||
*/
|
||||
public synchronized void setMaxRevVelocity(int maxRevVelocity) {
|
||||
int oldValue = velocityController.getMaxRevVelocity();
|
||||
velocityController.setMaxRevVelocity(maxRevVelocity);
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.MAX_REVERSE_VELOCITY.name(),
|
||||
oldValue,
|
||||
maxRevVelocity
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum forward velocity.
|
||||
*
|
||||
* @return The maximum forward velocity.
|
||||
*/
|
||||
public synchronized int getMaxFwdVelocity() {
|
||||
return velocityController.getMaxFwdVelocity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum forward velocity.
|
||||
*
|
||||
* @param maxFwdVelocity The new maximum forward velocity.
|
||||
*/
|
||||
public synchronized void setMaxFwdVelocity(int maxFwdVelocity) {
|
||||
int oldValue = velocityController.getMaxFwdVelocity();
|
||||
velocityController.setMaxFwdVelocity(maxFwdVelocity);
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.MAX_FORWARD_VELOCITY.name(),
|
||||
oldValue,
|
||||
maxFwdVelocity
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the vehicle is paused.
|
||||
*
|
||||
* @return paused
|
||||
*/
|
||||
public synchronized boolean isVehiclePaused() {
|
||||
return velocityController.isVehiclePaused();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the vehicle (i.e. set it's velocity to zero).
|
||||
*
|
||||
* @param pause True, if vehicle shall be paused. False, otherwise.
|
||||
*/
|
||||
public synchronized void setVehiclePaused(boolean pause) {
|
||||
boolean oldValue = velocityController.isVehiclePaused();
|
||||
velocityController.setVehiclePaused(pause);
|
||||
|
||||
getPropertyChangeSupport().firePropertyChange(
|
||||
Attribute.VEHICLE_PAUSED.name(),
|
||||
oldValue,
|
||||
pause
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the virtual vehicle's velocity controller.
|
||||
*
|
||||
* @return The virtual vehicle's velocity controller.
|
||||
*/
|
||||
@Nonnull
|
||||
public VelocityController getVelocityController() {
|
||||
return velocityController;
|
||||
}
|
||||
|
||||
private int parseOperatingTime(Vehicle vehicle) {
|
||||
String opTime = vehicle.getProperty(LoopbackAdapterConstants.PROPKEY_OPERATING_TIME);
|
||||
// Ensure it's a positive value.
|
||||
return Math.max(Parsers.tryParseString(opTime, 5000), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum acceleration. If the user did not specify any, 1000(m/s²) is returned.
|
||||
*
|
||||
* @param vehicle the vehicle
|
||||
* @return the maximum acceleration.
|
||||
*/
|
||||
private int parseAcceleration(Vehicle vehicle) {
|
||||
String acceleration = vehicle.getProperty(LoopbackAdapterConstants.PROPKEY_ACCELERATION);
|
||||
// Ensure it's a positive value.
|
||||
return Math.max(Parsers.tryParseString(acceleration, 500), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum decceleration. If the user did not specify any, 1000(m/s²) is returned.
|
||||
*
|
||||
* @param vehicle the vehicle
|
||||
* @return the maximum decceleration.
|
||||
*/
|
||||
private int parseDeceleration(Vehicle vehicle) {
|
||||
String deceleration = vehicle.getProperty(LoopbackAdapterConstants.PROPKEY_DECELERATION);
|
||||
// Ensure it's a negative value.
|
||||
return Math.min(Parsers.tryParseString(deceleration, -500), -1);
|
||||
}
|
||||
|
||||
private static String extractLoadOperation(Vehicle attachedVehicle) {
|
||||
String result = attachedVehicle.getProperty(LoopbackAdapterConstants.PROPKEY_LOAD_OPERATION);
|
||||
if (result == null) {
|
||||
result = LoopbackAdapterConstants.PROPVAL_LOAD_OPERATION_DEFAULT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String extractUnloadOperation(Vehicle attachedVehicle) {
|
||||
String result = attachedVehicle.getProperty(LoopbackAdapterConstants.PROPKEY_UNLOAD_OPERATION);
|
||||
if (result == null) {
|
||||
result = LoopbackAdapterConstants.PROPVAL_UNLOAD_OPERATION_DEFAULT;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification arguments to indicate some change.
|
||||
*/
|
||||
public enum Attribute {
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's single step mode setting.
|
||||
*/
|
||||
SINGLE_STEP_MODE,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's default operating time.
|
||||
*/
|
||||
OPERATING_TIME,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's maximum acceleration.
|
||||
*/
|
||||
ACCELERATION,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's maximum deceleration.
|
||||
*/
|
||||
DECELERATION,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's maximum forward velocity.
|
||||
*/
|
||||
MAX_FORWARD_VELOCITY,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's maximum reverse velocity.
|
||||
*/
|
||||
MAX_REVERSE_VELOCITY,
|
||||
/**
|
||||
* Indicates a change of the virtual vehicle's paused setting.
|
||||
*/
|
||||
VEHICLE_PAUSED,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import org.opentcs.drivers.vehicle.management.VehicleProcessModelTO;
|
||||
|
||||
/**
|
||||
* A serializable representation of a {@link LoopbackVehicleModel}.
|
||||
*/
|
||||
public class LoopbackVehicleModelTO
|
||||
extends
|
||||
VehicleProcessModelTO {
|
||||
|
||||
/**
|
||||
* Whether this communication adapter is in single step mode or not (i.e. in automatic mode).
|
||||
*/
|
||||
private boolean singleStepModeEnabled;
|
||||
/**
|
||||
* Indicates which operation is a loading operation.
|
||||
*/
|
||||
private String loadOperation;
|
||||
/**
|
||||
* Indicates which operation is an unloading operation.
|
||||
*/
|
||||
private String unloadOperation;
|
||||
/**
|
||||
* The time needed for executing operations.
|
||||
*/
|
||||
private int operatingTime;
|
||||
/**
|
||||
* The maximum acceleration.
|
||||
*/
|
||||
private int maxAcceleration;
|
||||
/**
|
||||
* The maximum deceleration.
|
||||
*/
|
||||
private int maxDeceleration;
|
||||
/**
|
||||
* The maximum forward velocity.
|
||||
*/
|
||||
private int maxFwdVelocity;
|
||||
/**
|
||||
* The maximum reverse velocity.
|
||||
*/
|
||||
private int maxRevVelocity;
|
||||
/**
|
||||
* Whether the vehicle is paused or not.
|
||||
*/
|
||||
private boolean vehiclePaused;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public LoopbackVehicleModelTO() {
|
||||
}
|
||||
|
||||
public boolean isSingleStepModeEnabled() {
|
||||
return singleStepModeEnabled;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setSingleStepModeEnabled(boolean singleStepModeEnabled) {
|
||||
this.singleStepModeEnabled = singleStepModeEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLoadOperation() {
|
||||
return loadOperation;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setLoadOperation(String loadOperation) {
|
||||
this.loadOperation = loadOperation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUnloadOperation() {
|
||||
return unloadOperation;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setUnloadOperation(String unloadOperation) {
|
||||
this.unloadOperation = unloadOperation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getOperatingTime() {
|
||||
return operatingTime;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setOperatingTime(int operatingTime) {
|
||||
this.operatingTime = operatingTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxAcceleration() {
|
||||
return maxAcceleration;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setMaxAcceleration(int maxAcceleration) {
|
||||
this.maxAcceleration = maxAcceleration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxDeceleration() {
|
||||
return maxDeceleration;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setMaxDeceleration(int maxDeceleration) {
|
||||
this.maxDeceleration = maxDeceleration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxFwdVelocity() {
|
||||
return maxFwdVelocity;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setMaxFwdVelocity(int maxFwdVelocity) {
|
||||
this.maxFwdVelocity = maxFwdVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxRevVelocity() {
|
||||
return maxRevVelocity;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setMaxRevVelocity(int maxRevVelocity) {
|
||||
this.maxRevVelocity = maxRevVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVehiclePaused() {
|
||||
return vehiclePaused;
|
||||
}
|
||||
|
||||
public LoopbackVehicleModelTO setVehiclePaused(boolean vehiclePaused) {
|
||||
this.vehiclePaused = vehiclePaused;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* This class provides methods for parsing.
|
||||
*/
|
||||
public class Parsers {
|
||||
|
||||
/**
|
||||
* Prevents instantiation of this utility class.
|
||||
*/
|
||||
private Parsers() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a String to an int. If <code>toParse</code> could not be parsed successfully then the
|
||||
* default value <code>retOnFail</code> is returned.
|
||||
*
|
||||
* @param toParse the <code>String</code> to be parsed.
|
||||
* @param retOnFail default value that is returned if the <code>String</code> could not be parsed.
|
||||
* @return if the <code>String</code> could be parsed then the int value of the
|
||||
* <code>String</code> is returned, else retOnFail
|
||||
*/
|
||||
public static int tryParseString(
|
||||
@Nullable
|
||||
String toParse,
|
||||
int retOnFail
|
||||
) {
|
||||
|
||||
if (toParse == null) {
|
||||
return retOnFail;
|
||||
}
|
||||
Integer parseTry = Ints.tryParse(toParse);
|
||||
if (parseTry == null) {
|
||||
return retOnFail;
|
||||
}
|
||||
return parseTry;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simulates the velocity of a vehicle depending on the length of the way and
|
||||
* the time it has moved already.
|
||||
*/
|
||||
public class VelocityController {
|
||||
|
||||
/**
|
||||
* This class's Logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VelocityController.class);
|
||||
/**
|
||||
* The maximum deceleration of the vehicle (in mm/s<sup>2</sup>).
|
||||
*/
|
||||
private int maxDeceleration;
|
||||
/**
|
||||
* The maximum acceleration of the vehicle (in mm/s<sup>2</sup>).
|
||||
*/
|
||||
private int maxAcceleration;
|
||||
/**
|
||||
* The maximum reverse velocity of the vehicle (in mm/s).
|
||||
*/
|
||||
private int maxRevVelocity;
|
||||
/**
|
||||
* The maximum forward velocity of the vehicle (in mm/s).
|
||||
*/
|
||||
private int maxFwdVelocity;
|
||||
/**
|
||||
* The current acceleration (in mm/s<sup>2</sup>).
|
||||
*/
|
||||
private int currentAcceleration;
|
||||
/**
|
||||
* The current velocity (in mm/s).
|
||||
*/
|
||||
private int currentVelocity;
|
||||
/**
|
||||
* The current position (in mm from the beginning of the current way entry).
|
||||
*/
|
||||
private long currentPosition;
|
||||
/**
|
||||
* The current time, relative to the point of time at which this velocity
|
||||
* controller was created.
|
||||
*/
|
||||
private long currentTime;
|
||||
/**
|
||||
* This controller's processing queue.
|
||||
*/
|
||||
private final Queue<WayEntry> wayEntries = new ArrayDeque<>();
|
||||
/**
|
||||
* True, if the vehicle has been paused, e.g. via the kernel gui
|
||||
* or a by a client message.
|
||||
*/
|
||||
private boolean paused;
|
||||
|
||||
/**
|
||||
* Creates a new VelocityController.
|
||||
*
|
||||
* @param maxDecel The maximum deceleration of the vehicle (in
|
||||
* mm/s<sup>2</sup>).
|
||||
* @param maxAccel The maximum acceleration of the vehicle (in
|
||||
* mm/s<sup>2</sup>).
|
||||
* @param maxRevVelo The maximum reverse velocity of the vehicle (in mm/s).
|
||||
* @param maxFwdVelo The maximum forward velocity of the vehicle (in mm/s).
|
||||
*/
|
||||
public VelocityController(
|
||||
int maxDecel,
|
||||
int maxAccel,
|
||||
int maxRevVelo,
|
||||
int maxFwdVelo
|
||||
) {
|
||||
maxDeceleration = maxDecel;
|
||||
maxAcceleration = maxAccel;
|
||||
maxRevVelocity = maxRevVelo;
|
||||
maxFwdVelocity = maxFwdVelo;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum deceleration.
|
||||
*
|
||||
* @return The maximum deceleration
|
||||
*/
|
||||
public int getMaxDeceleration() {
|
||||
return maxDeceleration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum deceleration.
|
||||
*
|
||||
* @param maxDeceleration The new maximum deceleration
|
||||
*/
|
||||
public void setMaxDeceleration(int maxDeceleration) {
|
||||
this.maxDeceleration = maxDeceleration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum acceleration.
|
||||
*
|
||||
* @return The maximum acceleration
|
||||
*/
|
||||
public int getMaxAcceleration() {
|
||||
return maxAcceleration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum acceleration.
|
||||
*
|
||||
* @param maxAcceleration The new maximum acceleration
|
||||
*/
|
||||
public void setMaxAcceleration(int maxAcceleration) {
|
||||
this.maxAcceleration = maxAcceleration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum reverse velocity.
|
||||
*
|
||||
* @return The maximum reverse velocity
|
||||
*/
|
||||
public int getMaxRevVelocity() {
|
||||
return maxRevVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum reverse velocity.
|
||||
*
|
||||
* @param maxRevVelocity The new maximum reverse velocity
|
||||
*/
|
||||
public void setMaxRevVelocity(int maxRevVelocity) {
|
||||
this.maxRevVelocity = maxRevVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum forward velocity.
|
||||
*
|
||||
* @return The maximum forward velocity
|
||||
*/
|
||||
public int getMaxFwdVelocity() {
|
||||
return maxFwdVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum forward velocity.
|
||||
*
|
||||
* @param maxFwdVelocity The new maximum forward velocity
|
||||
*/
|
||||
public void setMaxFwdVelocity(int maxFwdVelocity) {
|
||||
this.maxFwdVelocity = maxFwdVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the vehicle is paused.
|
||||
*
|
||||
* @return paused
|
||||
*/
|
||||
public boolean isVehiclePaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the vehicle (i.e. set it's velocity to zero).
|
||||
*
|
||||
* @param pause True, if vehicle shall be paused. False, otherwise.
|
||||
*/
|
||||
public void setVehiclePaused(boolean pause) {
|
||||
paused = pause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this controller's current velocity.
|
||||
*
|
||||
* @return This controller's current velocity.
|
||||
*/
|
||||
public int getCurrentVelocity() {
|
||||
return currentVelocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vehicle's current position (in mm from the beginning of the
|
||||
* current way entry.
|
||||
*
|
||||
* @return The vehicle's current position (in mm from the beginning of the
|
||||
* current way entry.
|
||||
*/
|
||||
public long getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time, relative to to the point of time at which this
|
||||
* controller was started.
|
||||
*
|
||||
* @return The current time, relative to to the point of time at which this
|
||||
* controller was started.
|
||||
*/
|
||||
public long getCurrentTime() {
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a way entry to this vehicle controller's processing queue.
|
||||
*
|
||||
* @param newEntry The way entry to add.
|
||||
*/
|
||||
public void addWayEntry(WayEntry newEntry) {
|
||||
requireNonNull(newEntry, "newEntry");
|
||||
|
||||
wayEntries.add(newEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the way entry this velocity controller is currently processing.
|
||||
*
|
||||
* @return The way entry this velocity controller is currently processing. If
|
||||
* the processing queue is currently empty, <code>null</code> is returned.
|
||||
*/
|
||||
public WayEntry getCurrentWayEntry() {
|
||||
return wayEntries.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if, and only if, there are way entries to be
|
||||
* processed in this velocity controller's queue.
|
||||
*
|
||||
* @return <code>true</code> if, and only if, there are way entries to be
|
||||
* processed in this velocity controller's queue.
|
||||
*/
|
||||
public boolean hasWayEntries() {
|
||||
return !wayEntries.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase this controller's current time by the given value and simulate
|
||||
* the events that would happen in this time frame.
|
||||
*
|
||||
* @param dt The time by which to advance this controller (in milliseconds).
|
||||
* Must be at least 1.
|
||||
*/
|
||||
public void advanceTime(int dt) {
|
||||
checkArgument(dt >= 1, "dt is less than 1: %d", dt);
|
||||
|
||||
final long oldPosition = currentPosition;
|
||||
final int oldVelocity = currentVelocity;
|
||||
final WayEntry curWayEntry = wayEntries.peek();
|
||||
if (curWayEntry == null || paused) {
|
||||
currentAcceleration = 0;
|
||||
currentVelocity = 0;
|
||||
}
|
||||
else {
|
||||
final int maxVelocity;
|
||||
final Vehicle.Orientation orientation = curWayEntry.vehicleOrientation;
|
||||
switch (orientation) {
|
||||
case FORWARD:
|
||||
maxVelocity = maxFwdVelocity;
|
||||
break;
|
||||
case BACKWARD:
|
||||
maxVelocity = maxRevVelocity;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unhandled orientation: {}, assuming forward.", orientation);
|
||||
maxVelocity = maxFwdVelocity;
|
||||
}
|
||||
final int targetVelocity = Math.min(curWayEntry.targetVelocity, maxVelocity);
|
||||
// Accelerate as quickly as possible.
|
||||
final long accelerationDistance = 10;
|
||||
// Recompute the acceleration to reach/keep the desired velocity.
|
||||
currentAcceleration
|
||||
= (currentVelocity == targetVelocity) ? 0
|
||||
: suitableAcceleration(targetVelocity, accelerationDistance);
|
||||
// Recompute current velocity.
|
||||
currentVelocity = oldVelocity + currentAcceleration * dt / 1000;
|
||||
// Recompute current position.
|
||||
currentPosition = oldPosition + oldVelocity * dt / 1000
|
||||
+ currentAcceleration * dt * dt / 1000000 / 2;
|
||||
// Check if we have left the way entry and entered the next.
|
||||
if (currentPosition >= curWayEntry.length) {
|
||||
currentPosition -= curWayEntry.length;
|
||||
wayEntries.poll();
|
||||
}
|
||||
}
|
||||
// The given time has now passed.
|
||||
currentTime += dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the acceleration (in mm/s<sup>2</sup>) needed for reaching a given
|
||||
* velocity exactly after travelling a given distance (respecting the current
|
||||
* velocity).
|
||||
*
|
||||
* @param targetVelocity The desired velocity (in mm/s).
|
||||
* @param travelDistance The distance after which the desired velocity is
|
||||
* supposed to be reached (in mm). Must be a positive value.
|
||||
* @return The acceleration needed for reaching the given velocity after
|
||||
* travelling the given distance.
|
||||
*/
|
||||
int suitableAcceleration(final int targetVelocity, final long travelDistance) {
|
||||
if (travelDistance < 1) {
|
||||
throw new IllegalArgumentException("travelDistance is less than 1");
|
||||
}
|
||||
final double v_current = currentVelocity;
|
||||
final double v_target = targetVelocity;
|
||||
final double s = travelDistance;
|
||||
// Compute travelling time.
|
||||
// XXX Divide by zero if (v_current == -v_target), especially if both are 0!
|
||||
final double t = s / (v_current + (v_target - v_current) / 2);
|
||||
LOG.debug(
|
||||
"t = " + t
|
||||
+ "; s = " + s
|
||||
+ "; v_current = " + v_current
|
||||
+ "; v_target = " + v_target
|
||||
);
|
||||
// Compute acceleration.
|
||||
int result = (int) ((v_target - v_current) / t);
|
||||
LOG.debug("result = " + result);
|
||||
if (result > maxAcceleration) {
|
||||
result = maxAcceleration;
|
||||
}
|
||||
else if (result < maxDeceleration) {
|
||||
result = maxDeceleration;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry in a vehicle controller's processing queue.
|
||||
*/
|
||||
public static class WayEntry
|
||||
implements
|
||||
Serializable {
|
||||
|
||||
/**
|
||||
* The length of the way to drive (in mm).
|
||||
*/
|
||||
private final long length;
|
||||
/**
|
||||
* The target velocity on this way (in mm/s).
|
||||
*/
|
||||
private final int targetVelocity;
|
||||
/**
|
||||
* The name of the destination point.
|
||||
*/
|
||||
private final String destPointName;
|
||||
/**
|
||||
* The vehicle's orientation on this way.
|
||||
*/
|
||||
private final Vehicle.Orientation vehicleOrientation;
|
||||
|
||||
/**
|
||||
* Creates a new WayEntry.
|
||||
*
|
||||
* @param length The length of the way to drive (in mm).
|
||||
* @param maxVelocity The maximum velocity on this way (in mm/s).
|
||||
* @param destPointName The name of the destination point.
|
||||
* @param orientation The vehicle's orientation on this way.
|
||||
*/
|
||||
public WayEntry(
|
||||
long length,
|
||||
int maxVelocity,
|
||||
String destPointName,
|
||||
Vehicle.Orientation orientation
|
||||
) {
|
||||
checkArgument(length > 0, "length is not > 0 but %s", length);
|
||||
this.length = length;
|
||||
if (maxVelocity < 1) {
|
||||
LOG.warn("maxVelocity is zero or negative, setting to 100");
|
||||
this.targetVelocity = 100;
|
||||
}
|
||||
else {
|
||||
this.targetVelocity = maxVelocity;
|
||||
}
|
||||
this.destPointName = requireNonNull(destPointName, "destPointName");
|
||||
this.vehicleOrientation = requireNonNull(orientation, "vehicleOrientation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the destination point.
|
||||
*
|
||||
* @return The name of the destination point.
|
||||
*/
|
||||
public String getDestPointName() {
|
||||
return destPointName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof WayEntry) {
|
||||
WayEntry other = (WayEntry) o;
|
||||
return other.length == length
|
||||
&& other.targetVelocity == targetVelocity
|
||||
&& destPointName.equals(other.destPointName)
|
||||
&& vehicleOrientation.equals(other.vehicleOrientation);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) (length ^ (length >>> 32))
|
||||
^ targetVelocity
|
||||
^ destPointName.hashCode()
|
||||
^ vehicleOrientation.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import org.opentcs.configuration.ConfigurationEntry;
|
||||
import org.opentcs.configuration.ConfigurationPrefix;
|
||||
|
||||
/**
|
||||
* Provides methods to configure to {@link LoopbackCommunicationAdapter}.
|
||||
*/
|
||||
@ConfigurationPrefix(VirtualVehicleConfiguration.PREFIX)
|
||||
public interface VirtualVehicleConfiguration {
|
||||
|
||||
/**
|
||||
* This configuration's prefix.
|
||||
*/
|
||||
String PREFIX = "virtualvehicle";
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Boolean",
|
||||
description = "Whether to enable to register/enable the loopback driver.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
|
||||
orderKey = "0_enable"
|
||||
)
|
||||
boolean enable();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = "The adapter's command queue capacity.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_NEW_PLANT_MODEL,
|
||||
orderKey = "1_attributes_1"
|
||||
)
|
||||
int commandQueueCapacity();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "String",
|
||||
description = "The string to be treated as a recharge operation.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.ON_NEW_PLANT_MODEL,
|
||||
orderKey = "1_attributes_2"
|
||||
)
|
||||
String rechargeOperation();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Double",
|
||||
description = "The rate at which the vehicle recharges in percent per second.",
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "1_attributes_3"
|
||||
)
|
||||
double rechargePercentagePerSecond();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Double",
|
||||
description = {
|
||||
"The simulation time factor.",
|
||||
"1.0 is real time, greater values speed up simulation."
|
||||
},
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "2_behaviour_1"
|
||||
)
|
||||
double simulationTimeFactor();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = {"The virtual vehicle's length in mm when it's loaded."},
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "2_behaviour_2"
|
||||
)
|
||||
int vehicleLengthLoaded();
|
||||
|
||||
@ConfigurationEntry(
|
||||
type = "Integer",
|
||||
description = {"The virtual vehicle's length in mm when it's unloaded."},
|
||||
changesApplied = ConfigurationEntry.ChangesApplied.INSTANTLY,
|
||||
orderKey = "2_behaviour_3"
|
||||
)
|
||||
int vehicleLengthUnloaded();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.MovementCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to notify the loopback adapter the last/current movement command failed.
|
||||
*/
|
||||
public class CurrentMovementCommandFailedCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public CurrentMovementCommandFailedCommand() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
MovementCommand failedCommand = adapter.getSentCommands().peek();
|
||||
if (failedCommand != null) {
|
||||
adapter.getProcessModel().commandFailed(adapter.getSentCommands().peek());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapterEvent;
|
||||
|
||||
/**
|
||||
* A command to publish {@link VehicleCommAdapterEvent}s.
|
||||
*/
|
||||
public class PublishEventCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The event to publish.
|
||||
*/
|
||||
private final VehicleCommAdapterEvent event;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param event The event to publish.
|
||||
*/
|
||||
public PublishEventCommand(
|
||||
@Nonnull
|
||||
VehicleCommAdapterEvent event
|
||||
) {
|
||||
this.event = requireNonNull(event, "event");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().publishEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's energy level.
|
||||
*/
|
||||
public class SetEnergyLevelCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The energy level to set.
|
||||
*/
|
||||
private final int level;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param level The energy level to set.
|
||||
*/
|
||||
public SetEnergyLevelCommand(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setEnergyLevel(level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.LoadHandlingDevice;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set the {@link LoadHandlingDevice}s attached to a vehicle.
|
||||
*/
|
||||
public class SetLoadHandlingDevicesCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The list of load handling devices.
|
||||
*/
|
||||
private final List<LoadHandlingDevice> devices;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param devices The list of load handling devices.
|
||||
*/
|
||||
public SetLoadHandlingDevicesCommand(
|
||||
@Nonnull
|
||||
List<LoadHandlingDevice> devices
|
||||
) {
|
||||
this.devices = requireNonNull(devices, "devices");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setLoadHandlingDevices(devices);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's orientation angle.
|
||||
*/
|
||||
public class SetOrientationAngleCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The orientation angle to set.
|
||||
*/
|
||||
private final double angle;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param angle The orientation angle to set.
|
||||
*/
|
||||
public SetOrientationAngleCommand(double angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setPose(
|
||||
adapter.getProcessModel().getPose().withOrientationAngle(angle)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's position.
|
||||
*/
|
||||
public class SetPositionCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The position to set.
|
||||
*/
|
||||
private final String position;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param position The position to set.
|
||||
*/
|
||||
public SetPositionCommand(
|
||||
@Nullable
|
||||
String position
|
||||
) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setPosition(position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.opentcs.data.model.Triple;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's precise position.
|
||||
*/
|
||||
public class SetPrecisePositionCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The percise position to set.
|
||||
*/
|
||||
private final Triple position;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param position The precise position to set.
|
||||
*/
|
||||
public SetPrecisePositionCommand(
|
||||
@Nullable
|
||||
Triple position
|
||||
) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setPose(
|
||||
adapter.getProcessModel().getPose().withPosition(position)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.virtualvehicle.LoopbackCommunicationAdapter;
|
||||
|
||||
/**
|
||||
* A command to enable/disable the comm adapter's single step mode.
|
||||
*/
|
||||
public class SetSingleStepModeEnabledCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* Whether to enable/disable single step mode.
|
||||
*/
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param enabled Whether to enable/disable single step mode.
|
||||
*/
|
||||
public SetSingleStepModeEnabledCommand(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
if (!(adapter instanceof LoopbackCommunicationAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoopbackCommunicationAdapter loopbackAdapter = (LoopbackCommunicationAdapter) adapter;
|
||||
loopbackAdapter.getProcessModel().setSingleStepModeEnabled(enabled);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's state.
|
||||
*/
|
||||
public class SetStateCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The vehicle state to set.
|
||||
*/
|
||||
private final Vehicle.State state;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param state The vehicle state to set.
|
||||
*/
|
||||
public SetStateCommand(
|
||||
@Nonnull
|
||||
Vehicle.State state
|
||||
) {
|
||||
this.state = requireNonNull(state, "state");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setState(state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.virtualvehicle.LoopbackCommunicationAdapter;
|
||||
|
||||
/**
|
||||
* A command to pause/unpause the vehicle.
|
||||
*/
|
||||
public class SetVehiclePausedCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* Whether to pause/unpause the vehicle.
|
||||
*/
|
||||
private final boolean paused;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param paused Whether to pause/unpause the vehicle.
|
||||
*/
|
||||
public SetVehiclePausedCommand(boolean paused) {
|
||||
this.paused = paused;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
if (!(adapter instanceof LoopbackCommunicationAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoopbackCommunicationAdapter loopbackAdapter = (LoopbackCommunicationAdapter) adapter;
|
||||
loopbackAdapter.getProcessModel().setVehiclePaused(paused);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
|
||||
/**
|
||||
* A command to set a vehicle's property.
|
||||
*/
|
||||
public class SetVehiclePropertyCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* The property key to set.
|
||||
*/
|
||||
private final String key;
|
||||
/**
|
||||
* The property value to set.
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param key The property key to set.
|
||||
* @param value The property value to set.
|
||||
*/
|
||||
public SetVehiclePropertyCommand(
|
||||
@Nonnull
|
||||
String key,
|
||||
@Nullable
|
||||
String value
|
||||
) {
|
||||
this.key = requireNonNull(key, "key");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
adapter.getProcessModel().setProperty(key, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.commands;
|
||||
|
||||
import org.opentcs.drivers.vehicle.AdapterCommand;
|
||||
import org.opentcs.drivers.vehicle.VehicleCommAdapter;
|
||||
import org.opentcs.virtualvehicle.LoopbackCommunicationAdapter;
|
||||
|
||||
/**
|
||||
* A command to trigger the comm adapter in single step mode.
|
||||
*/
|
||||
public class TriggerCommand
|
||||
implements
|
||||
AdapterCommand {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public TriggerCommand() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(VehicleCommAdapter adapter) {
|
||||
if (!(adapter instanceof LoopbackCommunicationAdapter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoopbackCommunicationAdapter loopbackAdapter = (LoopbackCommunicationAdapter) adapter;
|
||||
loopbackAdapter.trigger();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="messageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Message"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="label">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="comboBox">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<E>"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,277 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.ListCellRenderer;
|
||||
|
||||
/**
|
||||
* An input panel providing a dropdown list and optionally a message and a
|
||||
* label.
|
||||
*
|
||||
* The <code>Object</code> that is returned by {@link InputPanel#getInput} is
|
||||
* an object from the provided content list.
|
||||
*
|
||||
* @param <E> Type of the elements in the dropdown list
|
||||
*/
|
||||
public final class DropdownListInputPanel<E>
|
||||
extends
|
||||
InputPanel {
|
||||
|
||||
/**
|
||||
* Create a new panel.
|
||||
*
|
||||
* @param title Title of the panel.
|
||||
*/
|
||||
private DropdownListInputPanel(String title) {
|
||||
super(title);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureInput() {
|
||||
// If the combobox is editable and the input was entered using the jTextField and confirmed
|
||||
// using the enter button, then the textField's input is not yet saved as the comboBox
|
||||
// selection.
|
||||
// That's why it is safer to get the input from the textfield, if the combobox is editable.
|
||||
input = comboBox.isEditable() ? comboBox.getEditor().getItem() : comboBox.getSelectedItem();
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
/**
|
||||
* This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
label = new javax.swing.JLabel();
|
||||
comboBox = new javax.swing.JComboBox<>();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
messageLabel.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
messageLabel.setText("Message");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.gridwidth = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(messageLabel, gridBagConstraints);
|
||||
|
||||
label.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
label.setText("Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(label, gridBagConstraints);
|
||||
|
||||
comboBox.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(comboBox, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JComboBox<E> comboBox;
|
||||
private javax.swing.JLabel label;
|
||||
private javax.swing.JLabel messageLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
/**
|
||||
* See {@link InputPanel.Builder}.
|
||||
*
|
||||
* @param <E> Type of the elements in the dropdown list
|
||||
*/
|
||||
public static class Builder<E>
|
||||
implements
|
||||
InputPanel.Builder {
|
||||
|
||||
/**
|
||||
* The panel's title.
|
||||
*/
|
||||
private final String title;
|
||||
/**
|
||||
* The optional message.
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* The label for the dropdown list.
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* Content for the dropdown list.
|
||||
*/
|
||||
private final List<E> content;
|
||||
/**
|
||||
* Initially selected index of the dropdown list.
|
||||
* Default is 0.
|
||||
*/
|
||||
private int initialIndex;
|
||||
/**
|
||||
* Whether the combo box should be editable.
|
||||
*/
|
||||
private boolean editable;
|
||||
/**
|
||||
* Strategy for presenting the E-Objects in View.
|
||||
*/
|
||||
private ListCellRenderer<? super E> renderer;
|
||||
/**
|
||||
* Function for representing a selected element in the combo box.
|
||||
* This is basically a renderer for the combo box editor's content.
|
||||
*/
|
||||
private Function<E, String> selectionRepresenter = o -> o == null ? "" : o.toString();
|
||||
|
||||
/**
|
||||
* Create a new <code>Builder</code>.
|
||||
*
|
||||
* @param title The title of the panel.
|
||||
* @param content List of items.
|
||||
*/
|
||||
public Builder(String title, List<E> content) {
|
||||
this.title = requireNonNull(title, "title");
|
||||
this.content = requireNonNull(content, "content");
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputPanel build() {
|
||||
DropdownListInputPanel<E> panel = new DropdownListInputPanel<>(title);
|
||||
panel.messageLabel.setText(message);
|
||||
panel.label.setText(label);
|
||||
panel.comboBox.setEditable(editable);
|
||||
DefaultComboBoxModel<E> model = new DefaultComboBoxModel<>();
|
||||
panel.comboBox.setModel(model);
|
||||
|
||||
if (editable) {
|
||||
EditableComboBoxEditor<E> editor = new EditableComboBoxEditor<>(
|
||||
Collections.unmodifiableList(panel.getValidationListeners()),
|
||||
panel.comboBox, selectionRepresenter
|
||||
);
|
||||
panel.comboBox.setEditor(editor);
|
||||
model.addListDataListener(editor);
|
||||
}
|
||||
|
||||
//to notify the editor about new input
|
||||
for (E c : content) {
|
||||
model.addElement(c);
|
||||
}
|
||||
|
||||
if (this.renderer != null) {
|
||||
panel.comboBox.setRenderer(this.renderer);
|
||||
}
|
||||
if (!content.isEmpty()) {
|
||||
panel.comboBox.setSelectedIndex(initialIndex);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message of the panel.
|
||||
* The user of this method must take care for the line breaks in the message, as it is not
|
||||
* wrapped automatically!
|
||||
*
|
||||
* @param message The message.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the editable flag for the combo box.
|
||||
*
|
||||
* @param editable The editable flag.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setEditable(boolean editable) {
|
||||
this.editable = editable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CellRenderer for the dropdown list.
|
||||
* if none is set, then the default renderer will be used, which calls toString().
|
||||
*
|
||||
* @param renderer The renderer.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setRenderer(ListCellRenderer<? super E> renderer) {
|
||||
this.renderer = renderer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label of the panel.
|
||||
*
|
||||
* @param label The label.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial selected list entry.
|
||||
*
|
||||
* @param index Must be > 0, will have no effect otherwise.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setInitialSelection(int index) {
|
||||
if (index >= 0) {
|
||||
initialIndex = index;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial selected list entry.
|
||||
*
|
||||
* @param element Element to select. Selection remains unchanged if element is not in drop down
|
||||
* list or element is <code>null</code> and the content list does not allow null values.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setInitialSelection(Object element) {
|
||||
int index;
|
||||
try {
|
||||
index = content.indexOf(element);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
index = -1;
|
||||
}
|
||||
return setInitialSelection(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the representer for selected elements in the combo box.
|
||||
* This is basically a renderer for the combo box editor's content.
|
||||
* If none is set, a default representer will be used, which calls toString().
|
||||
*
|
||||
* @param selectionRepresenter Function for representing a selected element in the combo box.
|
||||
* @return The builder instance.
|
||||
*/
|
||||
public Builder<E> setSelectionRepresenter(Function<E, String> selectionRepresenter) {
|
||||
this.selectionRepresenter = selectionRepresenter;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.plaf.basic.BasicComboBoxEditor;
|
||||
|
||||
/**
|
||||
* An editor for editable combo boxes.
|
||||
*/
|
||||
public class EditableComboBoxEditor<E>
|
||||
extends
|
||||
BasicComboBoxEditor
|
||||
implements
|
||||
ListDataListener {
|
||||
|
||||
/**
|
||||
* Represents the model of the comboBox as a set.
|
||||
*/
|
||||
private final Set<E> content = new HashSet<>();
|
||||
/**
|
||||
* The relevant combobox.
|
||||
*/
|
||||
private final JComboBox<E> comboBox;
|
||||
/**
|
||||
* Returns the string representation for the combo box's selected item.
|
||||
*/
|
||||
private final Function<E, String> representer;
|
||||
|
||||
/**
|
||||
* Creates and instance and configures an {@link EditableComboBoxListener} for the editor.
|
||||
*
|
||||
* @param validationListeners validation listeners.
|
||||
* @param comboBox the comboBox that is edited.
|
||||
* @param representer Returns the string representation for the combo box's selected item.
|
||||
*/
|
||||
public EditableComboBoxEditor(
|
||||
List<ValidationListener> validationListeners,
|
||||
JComboBox<E> comboBox,
|
||||
Function<E, String> representer
|
||||
) {
|
||||
this.comboBox = requireNonNull(comboBox, "comboBox");
|
||||
this.representer = requireNonNull(representer, "representer");
|
||||
editor.getDocument().addDocumentListener(
|
||||
new EditableComboBoxListener<>(
|
||||
content,
|
||||
validationListeners,
|
||||
editor,
|
||||
representer
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void intervalAdded(ListDataEvent e) {
|
||||
loadContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void intervalRemoved(ListDataEvent e) {
|
||||
loadContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentsChanged(ListDataEvent e) {
|
||||
loadContent();
|
||||
}
|
||||
|
||||
private void loadContent() {
|
||||
//get the current comboBoxModel and add the modelelements to content
|
||||
ComboBoxModel<E> model = comboBox.getModel();
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
|
||||
content.add(model.getElementAt(i));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem() {
|
||||
for (E p : content) {
|
||||
if (representer.apply(p).equals(editor.getText())) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setItem(Object anObject) {
|
||||
editor.setText(representer.apply((E) anObject));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
/**
|
||||
* A validator for the input of the textfield.
|
||||
*/
|
||||
public class EditableComboBoxListener<E>
|
||||
implements
|
||||
DocumentListener {
|
||||
|
||||
private final JTextField textField;
|
||||
private final List<ValidationListener> validationListeners;
|
||||
private final Set<E> content;
|
||||
|
||||
/**
|
||||
* Returns the string representation for the combo box's selected item.
|
||||
*/
|
||||
private final Function<E, String> representer;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param content the elements of the comboBox' dropdownlist.
|
||||
* @param validationListeners the listeners to be notified about the validity of the user input.
|
||||
* @param textField the textfield with the input to be validated.
|
||||
* @param representer Returns the string representation for the combo box's selected item.
|
||||
*/
|
||||
public EditableComboBoxListener(
|
||||
Set<E> content,
|
||||
List<ValidationListener> validationListeners,
|
||||
JTextField textField,
|
||||
Function<E, String> representer
|
||||
) {
|
||||
|
||||
this.content = requireNonNull(content, "content");
|
||||
this.validationListeners = requireNonNull(validationListeners, "validationListeners");
|
||||
this.textField = requireNonNull(textField, "textField");
|
||||
this.representer = requireNonNull(representer, "representer");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
validate();
|
||||
}
|
||||
|
||||
private void notifyValidationListeners(boolean isValid) {
|
||||
for (ValidationListener valListener : validationListeners) {
|
||||
valListener.validityChanged(new ValidationEvent(this, isValid));
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
if (textField.getText().equals("")) {
|
||||
notifyValidationListeners(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (E element : content) {
|
||||
if (representer.apply(element).equals(textField.getText())) {
|
||||
notifyValidationListeners(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
notifyValidationListeners(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
|
||||
<Properties>
|
||||
<Property name="modal" type="boolean" value="true"/>
|
||||
<Property name="resizable" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<Events>
|
||||
<EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="dialogClosing"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="buttonPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
|
||||
<EmptyBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Last"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="okButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="inputDialog.button_ok.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="inputDialogOkButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="cancelButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="inputDialog.button_cancel.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="inputDialogCancelButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="resetButton">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="i18n/org/opentcs/commadapter/loopback/Bundle.properties" key="inputDialog.button_reset.text" replaceFormat="java.util.ResourceBundle.getBundle("{bundleNameSlashes}").getString("{key}")"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="inputDialogResetButton" noResource="true"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="resetButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,214 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
/**
|
||||
* A generic dialog for user input. It has two or three buttons
|
||||
* (<i>Ok</i>, <i>Cancel</i>, <i>reset</i>(optional)) and acts as a frame for an
|
||||
* {@link InputPanel}, that must be provided when
|
||||
* creating the dialog. <code>InputDialog</code> listens to
|
||||
* <code>InputPanel</code>'s {@link ValidationEvent} to dynamically
|
||||
* enable/disable the <i>ok</i>-button if the panel validates it's input.
|
||||
*/
|
||||
public class InputDialog
|
||||
extends
|
||||
javax.swing.JDialog
|
||||
implements
|
||||
ValidationListener {
|
||||
|
||||
/**
|
||||
* The panel that contains the content of the dialog.
|
||||
*/
|
||||
private final InputPanel panel;
|
||||
/**
|
||||
* Return status of the dialog. Will be set when the dialog is beeing closed.
|
||||
*/
|
||||
private ReturnStatus returnStatus;
|
||||
|
||||
/**
|
||||
* Enum values to indicate if the dialog accepted input from the user or
|
||||
* if the input was canceled.
|
||||
* TODO: no enum needed here?
|
||||
*/
|
||||
public enum ReturnStatus {
|
||||
|
||||
/**
|
||||
* The Dialog was cancelled. No input available.
|
||||
*/
|
||||
CANCELED,
|
||||
/**
|
||||
* The input was accepted and is available.
|
||||
*/
|
||||
ACCEPTED
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of <code>InputDialog</code>.
|
||||
*
|
||||
* @param panel the panel to be displayed in the dialog.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public InputDialog(InputPanel panel) {
|
||||
super();
|
||||
initComponents();
|
||||
setLocationRelativeTo(null);
|
||||
// Set up embedded panel
|
||||
this.panel = panel;
|
||||
setTitle(panel.getTitle());
|
||||
panel.setBorder(new EmptyBorder(6, 6, 10, 6));
|
||||
// Setup dialog
|
||||
getContentPane().add(panel, BorderLayout.CENTER);
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
if (!panel.isResetable()) {
|
||||
resetButton.setVisible(false);
|
||||
}
|
||||
pack();
|
||||
// Init validation value manually
|
||||
panel.addValidationListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validityChanged(ValidationEvent e) {
|
||||
okButton.setEnabled(e.valid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the return status of the dialog that indicates if there is input
|
||||
* available via {@link #getInput()}.
|
||||
* If the return status is {@link ReturnStatus#ACCEPTED ACCEPTED},
|
||||
* the panels input was captured
|
||||
* or reset and is available through {@link #getInput()}.
|
||||
* If the return status is {@link ReturnStatus#CANCELED CANCELLED},
|
||||
* {@link #getInput()} should <b>not</b>
|
||||
* be called as the dialog was canceled and there is no valid input available.
|
||||
* If the dialog wasn't closed yet, <code>null</code> will be returned.
|
||||
*
|
||||
* @return the return status
|
||||
*/
|
||||
public ReturnStatus getReturnStatus() {
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input from the embedded panel. This is the same as calling
|
||||
* {@link InputPanel#getInput()} directly.
|
||||
* Prior to calling this method you should check if there even is any input
|
||||
* (see {@link #getReturnStatus()}).
|
||||
*
|
||||
* @return The input from the panel
|
||||
*/
|
||||
public Object getInput() {
|
||||
return panel.getInput();
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
buttonPanel = new javax.swing.JPanel();
|
||||
okButton = new javax.swing.JButton();
|
||||
cancelButton = new javax.swing.JButton();
|
||||
resetButton = new javax.swing.JButton();
|
||||
|
||||
setModal(true);
|
||||
setResizable(false);
|
||||
addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
public void windowClosing(java.awt.event.WindowEvent evt) {
|
||||
dialogClosing(evt);
|
||||
}
|
||||
});
|
||||
|
||||
buttonPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
|
||||
okButton.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/commadapter/loopback/Bundle"); // NOI18N
|
||||
okButton.setText(bundle.getString("inputDialog.button_ok.text")); // NOI18N
|
||||
okButton.setName("inputDialogOkButton"); // NOI18N
|
||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
buttonPanel.add(okButton);
|
||||
|
||||
cancelButton.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
cancelButton.setText(bundle.getString("inputDialog.button_cancel.text")); // NOI18N
|
||||
cancelButton.setName("inputDialogCancelButton"); // NOI18N
|
||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
cancelButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
buttonPanel.add(cancelButton);
|
||||
|
||||
resetButton.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
resetButton.setText(bundle.getString("inputDialog.button_reset.text")); // NOI18N
|
||||
resetButton.setName("inputDialogResetButton"); // NOI18N
|
||||
resetButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
resetButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
buttonPanel.add(resetButton);
|
||||
|
||||
getContentPane().add(buttonPanel, java.awt.BorderLayout.PAGE_END);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
doClose(ReturnStatus.CANCELED);
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
panel.captureInput();
|
||||
doClose(ReturnStatus.ACCEPTED);
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetButtonActionPerformed
|
||||
panel.doReset();
|
||||
doClose(ReturnStatus.ACCEPTED);
|
||||
}//GEN-LAST:event_resetButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Handler for the WindowClosing event.
|
||||
* Called when the user closes the dialog via the X-Button or F4.
|
||||
*
|
||||
* @param evt WindowEvent
|
||||
*/
|
||||
private void dialogClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_dialogClosing
|
||||
doClose(ReturnStatus.CANCELED);
|
||||
}//GEN-LAST:event_dialogClosing
|
||||
|
||||
/**
|
||||
* Close the dialog properly and set the return status to indicate
|
||||
* how/why it was closed.
|
||||
*/
|
||||
private void doClose(ReturnStatus retStatus) {
|
||||
returnStatus = retStatus;
|
||||
setVisible(false);
|
||||
dispose();
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JPanel buttonPanel;
|
||||
private javax.swing.JButton cancelButton;
|
||||
private javax.swing.JButton okButton;
|
||||
private javax.swing.JButton resetButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base class for panels that provide input methods for the user and can be
|
||||
* embedded in an {@link InputDialog}.
|
||||
*/
|
||||
public abstract class InputPanel
|
||||
extends
|
||||
javax.swing.JPanel {
|
||||
|
||||
/**
|
||||
* Object to store the user's input. Must be explicitly set via captureInput()
|
||||
* or doReset(). What exactly this input is depends on the actual
|
||||
* implementation of InputPanel's subclass.
|
||||
*/
|
||||
protected Object input;
|
||||
/**
|
||||
* If true, the panel's state/input can be reset via doReset() to a default
|
||||
* value.
|
||||
* By default <code>InputPanels</code> are not resetable.
|
||||
*/
|
||||
protected boolean resetable;
|
||||
/**
|
||||
* List of ValidationListeners that will receive ValidationEvents.
|
||||
*/
|
||||
private final List<ValidationListener> validationListeners = new ArrayList<>();
|
||||
/**
|
||||
* Title of the panel. Might be used by the surrounding dialog.
|
||||
*/
|
||||
private final String title;
|
||||
/**
|
||||
* Indicates whether the current user input is valid.
|
||||
* If the panel validates the input this can be changed via setInputValid().
|
||||
*/
|
||||
private boolean inputValid = true;
|
||||
|
||||
/**
|
||||
* Create a new instance of InputPanel.
|
||||
*
|
||||
* @param title The title of this panel.
|
||||
*/
|
||||
public InputPanel(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the title of this panel.
|
||||
*
|
||||
* @return The title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link ValidationListener} that will receive
|
||||
* {@link ValidationEvent ValidationEvents}
|
||||
* whenever the validity of the input in this panel changes. The
|
||||
* {@link ValidationListener} will receive a {@link ValidationEvent} with the
|
||||
* current validity state immediately after beeing added.
|
||||
* If the panel does not validate it's input the validity will never change.
|
||||
*
|
||||
* @param listener The {@link ValidationListener}
|
||||
*/
|
||||
public void addValidationListener(ValidationListener listener) {
|
||||
validationListeners.add(listener);
|
||||
// Fire initial validation event for this listener
|
||||
listener.validityChanged(new ValidationEvent(this, inputValid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the input of the panel as valid/invalid and send
|
||||
* {@link ValidationEvent ValidationEvents}
|
||||
* to the attached {@link ValidationListener ValidationListeners}.
|
||||
* The Validity should only be changed via this method!
|
||||
*
|
||||
* @param valid true, if input is valid. false otherwise.
|
||||
*/
|
||||
protected void setInputValid(boolean valid) {
|
||||
boolean changed = valid != inputValid;
|
||||
inputValid = valid;
|
||||
if (changed) {
|
||||
ValidationEvent e = new ValidationEvent(this, valid);
|
||||
for (ValidationListener l : validationListeners) {
|
||||
l.validityChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The validation Listeners.
|
||||
*/
|
||||
public List<ValidationListener> getValidationListeners() {
|
||||
return validationListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current input in the panel is valid.
|
||||
* If the input isn't validated this will always return <code>true</code>.
|
||||
*
|
||||
* @see #addValidationListener
|
||||
* @return <code>true</code> if input is valid, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isInputValid() {
|
||||
return inputValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user input from the panel. If the input wasn't captured before
|
||||
* (see {@link #captureInput()}) null is returned. Otherwise it depends on the
|
||||
* concrete implementing panel what the input can look like.
|
||||
*
|
||||
* @return The input
|
||||
*/
|
||||
public Object getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the panel to get and store the user input which will be available
|
||||
* via {@link #getInput()} afterwards.
|
||||
* Usually this method should be called from the enclosing dialog when the
|
||||
* ok button is pressed. It is not intended to be used by the user of the
|
||||
* panel!
|
||||
*/
|
||||
protected abstract void captureInput();
|
||||
|
||||
/**
|
||||
* Returns whether the content of this panel can be reset to a default value.
|
||||
* If the panel is resetable the enclosing dialog might want to show a reset
|
||||
* button.
|
||||
*
|
||||
* @see #doReset()
|
||||
* @return panel is resetable?
|
||||
*/
|
||||
public boolean isResetable() {
|
||||
return resetable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the panel, that it should reset it's input values (probably because
|
||||
* the reset button in the enclosing dialog was pressed).
|
||||
* It's up to the specific panel itself to decide what is resetted.´
|
||||
* The default implementation does nothing.
|
||||
* It should be overwritten in subclasses if reset functionality is needed.
|
||||
*/
|
||||
public void doReset() {
|
||||
// Do nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An interface that can be used to implement the builder-pattern
|
||||
* (see Joshua Bloch's <i>Effective Java</i>).
|
||||
* <br>
|
||||
* As an <code>InputPanel</code> might have many required and/or optional
|
||||
* parameters it can be more convinient to use a Builder class instead of
|
||||
* public constructors.
|
||||
* A builder should implement a public constructor with required parameters
|
||||
* for the panel and public setters for optional parameters.
|
||||
* The <code>InputPanel</code> is created by the {@link #build} method.
|
||||
* <br>
|
||||
* For an example implementation see {@link SingleTextInputPanel.Builder}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Usage</b>:
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>Instanciate the builder, passing required parameters to the
|
||||
* constructor.</li>
|
||||
* <li>Set optional parameters via the other public methods.</li>
|
||||
* <li>Actually build the panel according to the previously specified
|
||||
* parameters using the build() method.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* <b>Note</b>:
|
||||
* The parameter methods should always return the builder itself, so the
|
||||
* creation of a panel can be done in a single statement (see the
|
||||
* <i>Builder-Pattern</i> in Joshua Bloch's <i>Effective Java</i>).
|
||||
* </p>
|
||||
*/
|
||||
public interface Builder {
|
||||
|
||||
/**
|
||||
* Finally build the {@link InputPanel} as described by this <code>Builder</code>.
|
||||
*
|
||||
* @return The created <code>InputPanel</code>.
|
||||
*/
|
||||
InputPanel build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="unitLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||
<Property name="text" type="java.lang.String" value="Unit-Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="label">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="inputField">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="initial Value"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="inputFieldFocusGained"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="messageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Message"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,278 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
/**
|
||||
* A general input panel with a text field and optionally:
|
||||
* <ul>
|
||||
* <li>a message/text</li>
|
||||
* <li>a label</li>
|
||||
* <li>a unit label for the input</li>
|
||||
* </ul>
|
||||
* The input of the text field can be validated
|
||||
* (see {@link Builder#enableValidation enableValidation}).
|
||||
* <br>
|
||||
* For instanciation the contained
|
||||
* {@link SingleTextInputPanel.Builder Builder}-class must be used.
|
||||
* <br>
|
||||
* The <code>Object</code> that is returned by {@link InputPanel#getInput} is
|
||||
* a <code>String</code> (the text in the text field).
|
||||
*/
|
||||
public final class SingleTextInputPanel
|
||||
extends
|
||||
TextInputPanel {
|
||||
|
||||
/**
|
||||
* If the panel is resetable this is the value the input is set to when
|
||||
* doReset() is called.
|
||||
*/
|
||||
private Object resetValue;
|
||||
|
||||
/**
|
||||
* Creates new instance of SingleTextInputPanel.
|
||||
* The given title is not used in the panel itselft but can be used by
|
||||
* the enclosing component.
|
||||
*
|
||||
* @param title The title of the panel.
|
||||
*/
|
||||
private SingleTextInputPanel(String title) {
|
||||
super(title);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable input validation against the given regular expression.
|
||||
*
|
||||
* @see InputPanel#addValidationListener
|
||||
* @param format A regular expression.
|
||||
*/
|
||||
private void enableInputValidation(String format) {
|
||||
if (format != null) {
|
||||
inputField.getDocument().addDocumentListener(new TextInputValidator(format));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureInput() {
|
||||
input = inputField.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doReset() {
|
||||
input = resetValue;
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
unitLabel = new javax.swing.JLabel();
|
||||
label = new javax.swing.JLabel();
|
||||
inputField = new javax.swing.JTextField();
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
unitLabel.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
unitLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||
unitLabel.setText("Unit-Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 2;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(unitLabel, gridBagConstraints);
|
||||
|
||||
label.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
label.setText("Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(label, gridBagConstraints);
|
||||
|
||||
inputField.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
inputField.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
|
||||
inputField.setText("initial Value");
|
||||
inputField.setPreferredSize(new java.awt.Dimension(70, 20));
|
||||
inputField.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusGained(java.awt.event.FocusEvent evt) {
|
||||
inputFieldFocusGained(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(inputField, gridBagConstraints);
|
||||
|
||||
messageLabel.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
messageLabel.setText("Message");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.gridwidth = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(messageLabel, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
private void inputFieldFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_inputFieldFocusGained
|
||||
inputField.selectAll();
|
||||
}//GEN-LAST:event_inputFieldFocusGained
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JTextField inputField;
|
||||
private javax.swing.JLabel label;
|
||||
private javax.swing.JLabel messageLabel;
|
||||
private javax.swing.JLabel unitLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
/**
|
||||
* See {@link InputPanel.Builder}.
|
||||
*/
|
||||
public static class Builder
|
||||
implements
|
||||
InputPanel.Builder {
|
||||
|
||||
/**
|
||||
* The panel's title.
|
||||
*/
|
||||
private final String title;
|
||||
/**
|
||||
* Label of for the text field.
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* Unit label of the text field.
|
||||
*/
|
||||
private String unitLabel;
|
||||
/**
|
||||
* Initial value for the text field.
|
||||
*/
|
||||
private String initialValue;
|
||||
/**
|
||||
* Message to be displayed in the panel.
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* Regex for validation of the text field's content.
|
||||
*/
|
||||
private String format;
|
||||
/**
|
||||
* Show a reset button in the panel.
|
||||
* Default is <code>false</code>.
|
||||
*/
|
||||
private boolean resetButton;
|
||||
/**
|
||||
* Value the input is reset to when the reset button is used.
|
||||
*/
|
||||
private Object resetValue;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param title Title of the panel.
|
||||
*/
|
||||
public Builder(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputPanel build() {
|
||||
SingleTextInputPanel panel = new SingleTextInputPanel(title);
|
||||
panel.enableInputValidation(format);
|
||||
panel.label.setText(label);
|
||||
panel.unitLabel.setText(unitLabel);
|
||||
panel.inputField.setText(initialValue);
|
||||
panel.messageLabel.setText(message);
|
||||
panel.resetable = resetButton;
|
||||
if (panel.resetable) {
|
||||
panel.resetValue = resetValue;
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label of the panel.
|
||||
*
|
||||
* @param label The Label
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial value for the text field of the panel.
|
||||
*
|
||||
* @param initialValue the initial value
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setInitialValue(String initialValue) {
|
||||
this.initialValue = initialValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text for the unit label of the panel.
|
||||
*
|
||||
* @param unitLabel the unit
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setUnitLabel(String unitLabel) {
|
||||
this.unitLabel = unitLabel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message of the panel.
|
||||
* The user of this method must take care for the line breaks in the message,
|
||||
* as it is not wrapped automatically!
|
||||
*
|
||||
* @param message the message
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the panel validate it's input.
|
||||
*
|
||||
* @param format The regular expression that will be used for validation.
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder enableValidation(String format) {
|
||||
this.format = format;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value the panel's input can be reset to.
|
||||
*
|
||||
* @param resetValue the reset value
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder enableResetButton(Object resetValue) {
|
||||
this.resetButton = true;
|
||||
this.resetValue = resetValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract base class for <code>InputPanels</code> that use text fields for input.
|
||||
* The main purpose of this class is to provide an easy to use way to validate
|
||||
* text inputs using it's nested class {@link TextInputPanel.TextInputValidator
|
||||
* TextInputValidator}.
|
||||
*/
|
||||
public abstract class TextInputPanel
|
||||
extends
|
||||
InputPanel {
|
||||
|
||||
/**
|
||||
* This class's logger.
|
||||
*/
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TextInputPanel.class);
|
||||
|
||||
/**
|
||||
* Create a new instance of <code>TextInputPanel</code>.
|
||||
*
|
||||
* @param title The title of this panel.
|
||||
*/
|
||||
public TextInputPanel(String title) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mark the input of the specified <code>Document</code> as valid/invalid
|
||||
* and send {@link ValidationEvent ValidationEvents} to the attached
|
||||
* {@link ValidationListener ValidationListeners}.
|
||||
* The <code>Document</code> should be related to an input component in this
|
||||
* panel.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Note</b>:<br>
|
||||
* The default implementation just forwards the call to
|
||||
* {@link InputPanel#setInputValid(boolean)} without respect to the
|
||||
* <code>Document</code>. Therefore subclasses with multiple Documents
|
||||
* should overwrite this method to for example check if <b>all</b> input
|
||||
* fields are valid and then decide if
|
||||
* {@link InputPanel#setInputValid(boolean)} should be called or not.
|
||||
* </p>
|
||||
*
|
||||
* @param valid true, if the content of the <code>Document</code> is valid
|
||||
* @param doc the <code>Document</code>
|
||||
*/
|
||||
protected void setInputValid(boolean valid, Document doc) {
|
||||
setInputValid(valid);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A {@link javax.swing.event.DocumentListener DocumentListener} that can be
|
||||
* used by subclasses of {@link TextInputPanel} to validate input in
|
||||
* {@link javax.swing.JTextField JTextFields} and other Components that
|
||||
* use {@link javax.swing.text.Document Documents}.
|
||||
* It listens to the DocumentEvents of a
|
||||
* <code>Document</code> and validates the Document's
|
||||
* content against a specified regular expression. Some convenient regular
|
||||
* expressions are provided as <code>public static</code> variables.
|
||||
* After validation {@link TextInputPanel#setInputValid(boolean,
|
||||
* javax.swing.text.Document)} is called.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Note:</b><br>
|
||||
* The, for convenience, provided regular expressions do
|
||||
* NOT check whether the given number really fits into the range of the
|
||||
* corresponding data type (e.g. <code>int</code> for <code>REGEX_INT</code>).
|
||||
* </p>
|
||||
*
|
||||
* @see TextInputPanel#setInputValid(boolean, javax.swing.text.Document)
|
||||
*/
|
||||
public class TextInputValidator
|
||||
implements
|
||||
DocumentListener {
|
||||
|
||||
/**
|
||||
* Regular expression that accepts a floating point number of arbitary length.
|
||||
* The decimal point and positions after it can be omitted.
|
||||
* <p>
|
||||
* Examples:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>3.0 is valid</li>
|
||||
* <li>-3 is valid</li>
|
||||
* <li>3. is invalid</li>
|
||||
* <li>.3 is invalid</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final String REGEX_FLOAT = "[-+]?[0-9]+(\\.[0-9]+)?";
|
||||
/**
|
||||
* Regular expression that accepts a positive floating point number of arbitrary length and 0.
|
||||
*/
|
||||
public static final String REGEX_FLOAT_POS = "\\+?[0-9]+(\\.[0-9]+)?";
|
||||
/**
|
||||
* Regular expression that accepts a negative floating point number of arbitrary length and 0.
|
||||
*/
|
||||
public static final String REGEX_FLOAT_NEG = "-[0-9]+(\\.[0-9]+)?|0+(\\.0+)?";
|
||||
/**
|
||||
* Regular expression that accepts any integer of arbitrary length.
|
||||
*/
|
||||
public static final String REGEX_INT = "[-+]?[0-9]+";
|
||||
/**
|
||||
* Regular expression that accepts any positive integer of arbitrary length and 0.
|
||||
*/
|
||||
public static final String REGEX_INT_POS = "\\+?[0-9]+";
|
||||
/**
|
||||
* Regular expression that accepts any negative integer of arbitrary length and 0.
|
||||
*/
|
||||
public static final String REGEX_INT_NEG = "-[0-9]+|0+";
|
||||
/**
|
||||
* Regular expression that accepts an integer in the interval [0,100].
|
||||
*/
|
||||
public static final String REGEX_INT_RANGE_0_100 = "[0-9]|[1-9][0-9]|100";
|
||||
/**
|
||||
* Regular expression that accepts anything except an empty (or whitespace-only) string.
|
||||
*/
|
||||
public static final String REGEX_NOT_EMPTY = ".*\\S.*";
|
||||
/**
|
||||
* Regular expression to validate the documents text against.
|
||||
*/
|
||||
private final String format;
|
||||
|
||||
/**
|
||||
* Create an instance of <code>TextInputValidator</code>.
|
||||
*
|
||||
* @param format The regular expression to use for validation.
|
||||
*/
|
||||
protected TextInputValidator(String format) {
|
||||
this.format = Objects.requireNonNull(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
validate(e.getDocument());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
validate(e.getDocument());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified <code>Document</code> and set the validation
|
||||
* state in the {@link InputPanel} accordingly.
|
||||
*
|
||||
* @param doc The <code>Document</code> to validate.
|
||||
*/
|
||||
private void validate(Document doc) {
|
||||
String text;
|
||||
try {
|
||||
text = doc.getText(0, doc.getLength());
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
LOG.warn("Exception retrieving document text", e);
|
||||
return;
|
||||
}
|
||||
setInputValid(text.matches(format), doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="messageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Message"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="inputField">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="inputFieldFocusGained"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JList" name="list">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="selectionMode" type="int" value="0"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,231 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
/**
|
||||
* An input panel with a text field for user input as well as a list of predefined
|
||||
* inputs to select from.
|
||||
*/
|
||||
public final class TextListInputPanel
|
||||
extends
|
||||
TextInputPanel {
|
||||
|
||||
/**
|
||||
* Creates a new instance TextListInputPanel.
|
||||
*
|
||||
* @param title the title of the panel
|
||||
*/
|
||||
private TextListInputPanel(String title) {
|
||||
super(title);
|
||||
resetable = false;
|
||||
initComponents();
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
Object selection = list.getSelectedValue();
|
||||
if (selection != null) {
|
||||
inputField.setText((String) selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureInput() {
|
||||
input = inputField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable input validation against the given regular expression.
|
||||
*
|
||||
* @see InputPanel#addValidationListener
|
||||
* @param format A regular expression.
|
||||
*/
|
||||
private void enableInputValidation(String format) {
|
||||
if (format != null) {
|
||||
inputField.getDocument().addDocumentListener(new TextInputValidator(format));
|
||||
}
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
inputField = new javax.swing.JTextField();
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
list = new javax.swing.JList<String>();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
messageLabel.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
messageLabel.setText("Message");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(messageLabel, gridBagConstraints);
|
||||
|
||||
inputField.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
inputField.setPreferredSize(new java.awt.Dimension(70, 20));
|
||||
inputField.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusGained(java.awt.event.FocusEvent evt) {
|
||||
inputFieldFocusGained(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(inputField, gridBagConstraints);
|
||||
|
||||
list.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
jScrollPane1.setViewportView(list);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
add(jScrollPane1, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
private void inputFieldFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_inputFieldFocusGained
|
||||
inputField.selectAll();
|
||||
}//GEN-LAST:event_inputFieldFocusGained
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
// FORMATTER:OFF
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JTextField inputField;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JList<String> list;
|
||||
private javax.swing.JLabel messageLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
/**
|
||||
* See {@link InputPanel.Builder}.
|
||||
*/
|
||||
public static class Builder
|
||||
implements
|
||||
InputPanel.Builder {
|
||||
|
||||
/**
|
||||
* The panel's title.
|
||||
*/
|
||||
private final String title;
|
||||
/**
|
||||
* The optional message.
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* Content for the dropdown list.
|
||||
*/
|
||||
private final List<String> content;
|
||||
/**
|
||||
* Regex for validation of the text field's content.
|
||||
*/
|
||||
private String format;
|
||||
/**
|
||||
* Initially selected index of the list.
|
||||
* Default is 0.
|
||||
*/
|
||||
private int initialIndex;
|
||||
|
||||
/**
|
||||
* Create a new <code>Builder</code>.
|
||||
*
|
||||
* @param title the title of the panel
|
||||
* @param content Predefined items to display in the panel's list
|
||||
*/
|
||||
public Builder(String title, List<String> content) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message of the panel.
|
||||
* The user of this method must take care for the line breaks in the message,
|
||||
* as it is not wrapped automatically!
|
||||
*
|
||||
* @param message the message
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the panel validate it's input.
|
||||
*
|
||||
* @param format The regular expression that will be used for validation.
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder enableValidation(String format) {
|
||||
this.format = format;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial selected list entry.
|
||||
*
|
||||
* @param index must be > 0, will have no effect otherwise
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setInitialSelection(int index) {
|
||||
if (index >= 0) {
|
||||
initialIndex = index;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial selected list entry.
|
||||
*
|
||||
* @param element Element to select. Selection remains unchanged if
|
||||
* element ist not in the list or element is
|
||||
* <code>null</code>.
|
||||
* @return the instance fo this <code>Builder</code>
|
||||
*/
|
||||
public Builder setInitialSelection(String element) {
|
||||
int index;
|
||||
try {
|
||||
index = content.indexOf(element);
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
index = -1;
|
||||
}
|
||||
return setInitialSelection(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextListInputPanel build() {
|
||||
TextListInputPanel panel = new TextListInputPanel(title);
|
||||
panel.enableInputValidation(format);
|
||||
panel.messageLabel.setText(message);
|
||||
panel.list.setListData(content.toArray(new String[content.size()]));
|
||||
panel.list.setSelectedIndex(initialIndex);
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="unitLabel3">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||
<Property name="text" type="java.lang.String" value="Unit-Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="label3">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="inputField3">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="initial Value"/>
|
||||
<Property name="name" type="java.lang.String" value="inputField3" noResource="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/>
|
||||
</AccessibilityProperties>
|
||||
<Events>
|
||||
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="inputField3FocusGained"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="messageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Message"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="label1">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="inputField1">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="initial Value"/>
|
||||
<Property name="name" type="java.lang.String" value="inputField1" noResource="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/>
|
||||
</AccessibilityProperties>
|
||||
<Events>
|
||||
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="inputField1FocusGained"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="unitLabel1">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||
<Property name="text" type="java.lang.String" value="Unit-Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="label2">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" value="Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="inputField2">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||
<Property name="text" type="java.lang.String" value="initial Value"/>
|
||||
<Property name="name" type="java.lang.String" value="inputField2" noResource="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/>
|
||||
</AccessibilityProperties>
|
||||
<Events>
|
||||
<EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="inputField2FocusGained"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="unitLabel2">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Arial" size="11" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||
<Property name="text" type="java.lang.String" value="Unit-Label"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,498 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import javax.swing.text.Document;
|
||||
|
||||
/**
|
||||
* General input panel with three text fields and optionally:
|
||||
* <ul>
|
||||
* <li>a message/text</li>
|
||||
* <li>labels for the text fields</li>
|
||||
* <li>unit labels for the text fields</li>
|
||||
* </ul>
|
||||
* The input of the text fields can be validated
|
||||
* (see {@link Builder#enableValidation enableValidation}).
|
||||
* For instanciation the contained
|
||||
* {@link TripleTextInputPanel.Builder Builder}-class must be used.
|
||||
* The <code>Object</code> that is returned by {@link InputPanel#getInput} is
|
||||
* an <code>Array</code> of three <code>Strings</code>.
|
||||
*/
|
||||
public final class TripleTextInputPanel
|
||||
extends
|
||||
TextInputPanel {
|
||||
|
||||
/**
|
||||
* If the panel is resetable this is the value the input is set to when
|
||||
* doReset() is called.
|
||||
*/
|
||||
private Object resetValue;
|
||||
/**
|
||||
* Flag indicating if the content of the first text field is a valid input.
|
||||
*/
|
||||
private boolean inputField1Valid = true;
|
||||
/**
|
||||
* Flag indicating if the content of the second text field is a valid input.
|
||||
*/
|
||||
private boolean inputField2Valid = true;
|
||||
/**
|
||||
* Flag indicating if the content of the third text field is a valid input.
|
||||
*/
|
||||
private boolean inputField3Valid = true;
|
||||
|
||||
/**
|
||||
* Create a new <code>TripleTextInputPanel</code>.
|
||||
*
|
||||
* @param title Title of the panel
|
||||
*/
|
||||
private TripleTextInputPanel(String title) {
|
||||
super(title);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable input validation against the given regular expressions.
|
||||
* If a format string is <code>null</code> the related text field is not
|
||||
* validated.
|
||||
*
|
||||
* @see InputPanel#addValidationListener
|
||||
* @param format1 A regular expression for the first text field.
|
||||
* @param format2 A regular expression for the second text field.
|
||||
* @param format3 A regular expression for the third text field.
|
||||
*/
|
||||
private void enableInputValidation(
|
||||
String format1,
|
||||
String format2,
|
||||
String format3
|
||||
) {
|
||||
if (format1 != null) {
|
||||
inputField1.getDocument().addDocumentListener(new TextInputValidator(format1));
|
||||
}
|
||||
if (format2 != null) {
|
||||
inputField2.getDocument().addDocumentListener(new TextInputValidator(format2));
|
||||
}
|
||||
if (format3 != null) {
|
||||
inputField3.getDocument().addDocumentListener(new TextInputValidator(format3));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void captureInput() {
|
||||
input = new String[]{
|
||||
inputField1.getText(),
|
||||
inputField2.getText(),
|
||||
inputField3.getText()
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doReset() {
|
||||
input = resetValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the input of the specified <code>Document</code> as valid, if this
|
||||
* Document belongs to one of the three text fields in this panel.
|
||||
* If <code>valid</code> is <code>true</code> the validity of the other
|
||||
* two documents is checked, too. Only if all three text fields contain valid
|
||||
* input, the whole input of the panel is marked as valid.
|
||||
*
|
||||
* @see TextInputPanel#setInputValid(boolean, javax.swing.text.Document)
|
||||
* @param valid true, if the content of the <code>Document</code> is valid
|
||||
* @param doc the <code>Document</code>
|
||||
*/
|
||||
@Override
|
||||
protected void setInputValid(boolean valid, Document doc) {
|
||||
// Find out to which input field the document belongs and check the others
|
||||
boolean allValid = valid;
|
||||
if (doc == inputField1.getDocument()) {
|
||||
inputField1Valid = valid;
|
||||
if (!(inputField2Valid && inputField3Valid)) {
|
||||
allValid = false;
|
||||
}
|
||||
}
|
||||
else if (doc == inputField2.getDocument()) {
|
||||
inputField2Valid = valid;
|
||||
if (!(inputField1Valid && inputField3Valid)) {
|
||||
allValid = false;
|
||||
}
|
||||
}
|
||||
else if (doc == inputField3.getDocument()) {
|
||||
inputField3Valid = valid;
|
||||
if (!(inputField1Valid && inputField2Valid)) {
|
||||
allValid = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
allValid = false;
|
||||
}
|
||||
setInputValid(allValid);
|
||||
}
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
unitLabel3 = new javax.swing.JLabel();
|
||||
label3 = new javax.swing.JLabel();
|
||||
inputField3 = new javax.swing.JTextField();
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
label1 = new javax.swing.JLabel();
|
||||
inputField1 = new javax.swing.JTextField();
|
||||
unitLabel1 = new javax.swing.JLabel();
|
||||
label2 = new javax.swing.JLabel();
|
||||
inputField2 = new javax.swing.JTextField();
|
||||
unitLabel2 = new javax.swing.JLabel();
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
unitLabel3.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
unitLabel3.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||
unitLabel3.setText("Unit-Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 2;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(unitLabel3, gridBagConstraints);
|
||||
|
||||
label3.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
label3.setText("Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(label3, gridBagConstraints);
|
||||
|
||||
inputField3.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
inputField3.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
|
||||
inputField3.setText("initial Value");
|
||||
inputField3.setName("inputField3"); // NOI18N
|
||||
inputField3.setPreferredSize(new java.awt.Dimension(70, 20));
|
||||
inputField3.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusGained(java.awt.event.FocusEvent evt) {
|
||||
inputField3FocusGained(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(inputField3, gridBagConstraints);
|
||||
inputField3.getAccessibleContext().setAccessibleName("");
|
||||
|
||||
messageLabel.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
messageLabel.setText("Message");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.gridwidth = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(messageLabel, gridBagConstraints);
|
||||
|
||||
label1.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
label1.setText("Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(label1, gridBagConstraints);
|
||||
|
||||
inputField1.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
inputField1.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
|
||||
inputField1.setText("initial Value");
|
||||
inputField1.setName("inputField1"); // NOI18N
|
||||
inputField1.setPreferredSize(new java.awt.Dimension(70, 20));
|
||||
inputField1.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusGained(java.awt.event.FocusEvent evt) {
|
||||
inputField1FocusGained(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(inputField1, gridBagConstraints);
|
||||
inputField1.getAccessibleContext().setAccessibleName("");
|
||||
|
||||
unitLabel1.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
unitLabel1.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||
unitLabel1.setText("Unit-Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 2;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(unitLabel1, gridBagConstraints);
|
||||
|
||||
label2.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
label2.setText("Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(label2, gridBagConstraints);
|
||||
|
||||
inputField2.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
inputField2.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
|
||||
inputField2.setText("initial Value");
|
||||
inputField2.setName("inputField2"); // NOI18N
|
||||
inputField2.setPreferredSize(new java.awt.Dimension(70, 20));
|
||||
inputField2.addFocusListener(new java.awt.event.FocusAdapter() {
|
||||
public void focusGained(java.awt.event.FocusEvent evt) {
|
||||
inputField2FocusGained(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(inputField2, gridBagConstraints);
|
||||
inputField2.getAccessibleContext().setAccessibleName("");
|
||||
|
||||
unitLabel2.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
|
||||
unitLabel2.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||
unitLabel2.setText("Unit-Label");
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 2;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
|
||||
add(unitLabel2, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
private void inputField1FocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_inputField1FocusGained
|
||||
inputField1.selectAll();
|
||||
}//GEN-LAST:event_inputField1FocusGained
|
||||
|
||||
private void inputField2FocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_inputField2FocusGained
|
||||
inputField2.selectAll();
|
||||
}//GEN-LAST:event_inputField2FocusGained
|
||||
|
||||
private void inputField3FocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_inputField3FocusGained
|
||||
inputField3.selectAll();
|
||||
}//GEN-LAST:event_inputField3FocusGained
|
||||
|
||||
// FORMATTER:OFF
|
||||
// CHECKSTYLE:OFF
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JTextField inputField1;
|
||||
private javax.swing.JTextField inputField2;
|
||||
private javax.swing.JTextField inputField3;
|
||||
private javax.swing.JLabel label1;
|
||||
private javax.swing.JLabel label2;
|
||||
private javax.swing.JLabel label3;
|
||||
private javax.swing.JLabel messageLabel;
|
||||
private javax.swing.JLabel unitLabel1;
|
||||
private javax.swing.JLabel unitLabel2;
|
||||
private javax.swing.JLabel unitLabel3;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
// CHECKSTYLE:ON
|
||||
// FORMATTER:ON
|
||||
|
||||
/**
|
||||
* See {@link InputPanel.Builder}.
|
||||
*/
|
||||
public static class Builder
|
||||
implements
|
||||
InputPanel.Builder {
|
||||
|
||||
/**
|
||||
* The panel's title.
|
||||
*/
|
||||
private final String title;
|
||||
/**
|
||||
* Message to be displayed in the panel.
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* Labels of for the text fields.
|
||||
*/
|
||||
private final String[] labels = new String[3];
|
||||
/**
|
||||
* Unit labels of the text fields.
|
||||
*/
|
||||
private final String[] unitLabels = new String[3];
|
||||
/**
|
||||
* Initial values for the text fields.
|
||||
*/
|
||||
private final String[] initialValues = new String[3];
|
||||
/**
|
||||
* Regular expressions for validation of the text field contents.
|
||||
*/
|
||||
private final String[] formats = new String[3];
|
||||
/**
|
||||
* Show a reset button in the panel.
|
||||
* Default is <code>false</code>.
|
||||
*/
|
||||
private boolean resetButton;
|
||||
/**
|
||||
* Value the input is reset to when the reset button is used.
|
||||
*/
|
||||
private Object resetValue;
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* @param title Title of the panel.
|
||||
*/
|
||||
public Builder(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputPanel build() {
|
||||
TripleTextInputPanel panel = new TripleTextInputPanel(title);
|
||||
panel.enableInputValidation(formats[0], formats[1], formats[2]);
|
||||
panel.label1.setText(labels[0]);
|
||||
panel.label2.setText(labels[1]);
|
||||
panel.label3.setText(labels[2]);
|
||||
panel.unitLabel1.setText(unitLabels[0]);
|
||||
panel.unitLabel2.setText(unitLabels[1]);
|
||||
panel.unitLabel3.setText(unitLabels[2]);
|
||||
panel.inputField1.setText(initialValues[0]);
|
||||
panel.inputField2.setText(initialValues[1]);
|
||||
panel.inputField3.setText(initialValues[2]);
|
||||
panel.messageLabel.setText(message);
|
||||
panel.resetable = resetButton;
|
||||
if (panel.resetable) {
|
||||
panel.resetValue = resetValue;
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the labels for the text fields.
|
||||
* Passing <code>null</code> means there should not be such a label.
|
||||
*
|
||||
* @param label1 The label of the first text field
|
||||
* @param label2 The label of the second text field
|
||||
* @param label3 The label of the third text field
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setLabels(String label1, String label2, String label3) {
|
||||
labels[0] = label1;
|
||||
labels[1] = label2;
|
||||
labels[2] = label3;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the same initial value for all three text fields.
|
||||
*
|
||||
* @param value The initial value.
|
||||
* @return the isntance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setInitialValues(String value) {
|
||||
return setInitialValues(value, value, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial values for the text fields of the panel
|
||||
* Passing <code>null</code> means there should not be an initial value
|
||||
* for this text field.
|
||||
*
|
||||
* @param val1 The initial value of the first text field
|
||||
* @param val2 The initial value of the second text field
|
||||
* @param val3 The initial value of the third text field
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setInitialValues(String val1, String val2, String val3) {
|
||||
initialValues[0] = val1;
|
||||
initialValues[1] = val2;
|
||||
initialValues[2] = val3;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the same text for the unit label for all three text fields.
|
||||
*
|
||||
* @param unit The unit
|
||||
* @return the isntance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setUnitLabels(String unit) {
|
||||
return setUnitLabels(unit, unit, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the text for the unit labels of the panel.
|
||||
* Passing <code>null</code> means there should not be a unit label for
|
||||
* the corresponding text field.
|
||||
*
|
||||
* @param unit1 The unit of the first text field
|
||||
* @param unit2 The unit of the second text field
|
||||
* @param unit3 The unit of the third text field
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setUnitLabels(String unit1, String unit2, String unit3) {
|
||||
unitLabels[0] = unit1;
|
||||
unitLabels[1] = unit2;
|
||||
unitLabels[2] = unit3;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message of the panel.
|
||||
* The user of this method must take care for the line breaks in the message,
|
||||
* as it is not wrapped automatically!
|
||||
*
|
||||
* @param message the message
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder enableValidation(String format) {
|
||||
return enableValidation(format, format, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the panel validate it's input by using the specified regular
|
||||
* expressions for the text fields.
|
||||
* Passing null as an argument means that the corresponding text field
|
||||
* should not be validated.
|
||||
*
|
||||
* @param format1 The regular expression that will be used for validation in
|
||||
* the first text field.
|
||||
* @param format2 The regular expression that will be used for validation in
|
||||
* the second text field.
|
||||
* @param format3 The regular expression that will be used for validation in
|
||||
* the third text field.
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder enableValidation(
|
||||
String format1,
|
||||
String format2,
|
||||
String format3
|
||||
) {
|
||||
formats[0] = format1;
|
||||
formats[1] = format2;
|
||||
formats[2] = format3;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value the panel's input can be reset to.
|
||||
*
|
||||
* @param resetValue the reset value
|
||||
* @return the instance of this <code>Builder</code>
|
||||
*/
|
||||
public Builder enableResetButton(Object resetValue) {
|
||||
this.resetButton = true;
|
||||
this.resetValue = resetValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* An event holding a single boolean variable indicating if something is valid.
|
||||
*/
|
||||
public class ValidationEvent
|
||||
extends
|
||||
EventObject {
|
||||
|
||||
/**
|
||||
* Validation state.
|
||||
*/
|
||||
private final boolean valid;
|
||||
|
||||
/**
|
||||
* Create a new <code>ValidationEvent</code>.
|
||||
*
|
||||
* @param source The source of the event.
|
||||
* @param valid The state of validation that should be reported by this event.
|
||||
*/
|
||||
public ValidationEvent(Object source, boolean valid) {
|
||||
super(source);
|
||||
this.valid = valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the state of validation.
|
||||
*
|
||||
* @return valid
|
||||
*/
|
||||
public boolean valid() {
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
* A listener interface for {@link ValidationEvent ValidationEvents}.
|
||||
*/
|
||||
public interface ValidationListener
|
||||
extends
|
||||
EventListener {
|
||||
|
||||
/**
|
||||
* Should be called when the state of validation changed.
|
||||
*
|
||||
* @param e The ValidationEvent containing validation information.
|
||||
*/
|
||||
void validityChanged(ValidationEvent e);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
* Generic GUI components for input dialogs.
|
||||
*/
|
||||
package org.opentcs.virtualvehicle.inputcomponents;
|
||||
@@ -0,0 +1,6 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
* Classes for emulating the behaviour of a physical vehicle.
|
||||
*/
|
||||
package org.opentcs.virtualvehicle;
|
||||
10
opentcs-commadapter-loopback/src/main/resources/REUSE.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
# SPDX-FileCopyrightText: The openTCS Authors
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
version = 1
|
||||
|
||||
[[annotations]]
|
||||
path = ["**/*.gif", "**/*.jpg", "**/*.png", "**/*.svg"]
|
||||
precedence = "closest"
|
||||
SPDX-FileCopyrightText = "The openTCS Authors"
|
||||
SPDX-License-Identifier = "CC-BY-4.0"
|
||||
@@ -0,0 +1,44 @@
|
||||
# SPDX-FileCopyrightText: The openTCS Authors
|
||||
# SPDX-License-Identifier: CC-BY-4.0
|
||||
|
||||
inputDialog.button_cancel.text=Cancel
|
||||
inputDialog.button_ok.text=Ok
|
||||
inputDialog.button_reset.text=Reset
|
||||
loopbackCommAdapterPanel.accessibleName=Loopback options
|
||||
loopbackCommAdapterPanel.button_dispatchEvent.text=Dispatch event
|
||||
loopbackCommAdapterPanel.button_failCurrentCommand.text=Fail current command
|
||||
loopbackCommAdapterPanel.button_nextStep.text=Next step
|
||||
loopbackCommAdapterPanel.button_setProperty.text = Apply
|
||||
loopbackCommAdapterPanel.checkBox_commandProcessingAutomatic.text=Automatic mode
|
||||
loopbackCommAdapterPanel.checkBox_commandProcessingManual.text=Single step/manual mode
|
||||
loopbackCommAdapterPanel.checkBox_enableAdapter.text=Enable loopback adapter
|
||||
loopbackCommAdapterPanel.checkBox_includeAppendix.text=Include message as appendix:
|
||||
loopbackCommAdapterPanel.dialog_setEnergyLevel.title=Set energy level
|
||||
loopbackCommAdapterPanel.dialog_setOrientationAngle.title=Set orientation angle
|
||||
loopbackCommAdapterPanel.dialog_setPosition.title=Set vehicle position
|
||||
loopbackCommAdapterPanel.dialog_setPrecisePosition.title=Set precise position
|
||||
loopbackCommAdapterPanel.dialog_setState.title=Set vehicle state
|
||||
loopbackCommAdapterPanel.label_energyLevel.text=Energy level:
|
||||
loopbackCommAdapterPanel.label_maximumAcceleration.text=Acceleration:
|
||||
loopbackCommAdapterPanel.label_maximumDeceleration.text=Deceleration:
|
||||
loopbackCommAdapterPanel.label_maximumForwardVelocity.text=Max. forward velocity:
|
||||
loopbackCommAdapterPanel.label_maximumReverseVelocity.text=Max. reverse velocity:
|
||||
loopbackCommAdapterPanel.label_operatingTime.text=Operating time:
|
||||
loopbackCommAdapterPanel.label_orientationAngle.text=Orientation:
|
||||
loopbackCommAdapterPanel.label_pauseVehicle.text=Pause vehicle:
|
||||
loopbackCommAdapterPanel.label_position.text=Position:
|
||||
loopbackCommAdapterPanel.label_precisePosition.text=Precise position:
|
||||
loopbackCommAdapterPanel.label_propertyKey.text=Key:
|
||||
loopbackCommAdapterPanel.label_state.text=State:
|
||||
loopbackCommAdapterPanel.panel_adapterStatus.border.title=Adapter status
|
||||
loopbackCommAdapterPanel.panel_commandProcessing.border.title=Command processing
|
||||
loopbackCommAdapterPanel.panel_eventDispatching.title=Event dispatching
|
||||
loopbackCommAdapterPanel.panel_loadHandlingDevice.border.title=Load handling device
|
||||
loopbackCommAdapterPanel.panel_vehicleProperties.border.title=Vehicle properties
|
||||
loopbackCommAdapterPanel.panel_vehicleProperty.border.title = Vehicle property
|
||||
loopbackCommAdapterPanel.panel_vehicleStatus.border.title=Current position/state
|
||||
loopbackCommAdapterPanel.radioButton_removeProperty.text=Remove property
|
||||
loopbackCommAdapterPanel.radioButton_setProperty.text=Set this value:
|
||||
loopbackCommAdapterPanel.textArea_precisePosition.positionNotSetPlaceholder=-
|
||||
loopbackCommAdapterPanel.textField_orientationAngle.angleNotSetPlaceholder=-
|
||||
loopbackCommunicationAdapterDescription.description=Loopback adapter (virtual vehicle)
|
||||
@@ -0,0 +1,43 @@
|
||||
# SPDX-FileCopyrightText: The openTCS Authors
|
||||
# SPDX-License-Identifier: CC-BY-4.0
|
||||
|
||||
inputDialog.button_cancel.text=Abbrechen
|
||||
inputDialog.button_ok.text=Ok
|
||||
inputDialog.button_reset.text=Zur\u00fccksetzen
|
||||
loopbackCommAdapterPanel.accessibleName=Loopback-Optionen
|
||||
loopbackCommAdapterPanel.button_dispatchEvent.text=Event versenden
|
||||
loopbackCommAdapterPanel.button_nextStep.text=N\u00e4chster Schritt
|
||||
loopbackCommAdapterPanel.button_setProperty.text = Anwenden
|
||||
loopbackCommAdapterPanel.checkBox_commandProcessingAutomatic.text=Automatik
|
||||
loopbackCommAdapterPanel.checkBox_commandProcessingManual.text=Manuell
|
||||
loopbackCommAdapterPanel.checkBox_enableAdapter.text=Loopback-Treiber einschalten
|
||||
loopbackCommAdapterPanel.checkBox_includeAppendix.text=Nachricht als Anhang hinzuf\u00fcgen:
|
||||
loopbackCommAdapterPanel.dialog_setEnergyLevel.title=Energie-Level setzen
|
||||
loopbackCommAdapterPanel.dialog_setOrientationAngle.title=Orientierung setzen
|
||||
loopbackCommAdapterPanel.dialog_setPosition.title=Fahrzeug-Position setzen
|
||||
loopbackCommAdapterPanel.dialog_setPrecisePosition.title=Exakte Position setzen
|
||||
loopbackCommAdapterPanel.dialog_setState.title=Fahrzeug-Zustand setzen
|
||||
loopbackCommAdapterPanel.label_energyLevel.text=Energie-Level:
|
||||
loopbackCommAdapterPanel.label_maximumAcceleration.text=Beschleunigung:
|
||||
loopbackCommAdapterPanel.label_maximumDeceleration.text=Abbremsung:
|
||||
loopbackCommAdapterPanel.label_maximumForwardVelocity.text=Max. Vorw\u00e4rts-Geschwindigkeit:
|
||||
loopbackCommAdapterPanel.label_maximumReverseVelocity.text=Max. R\u00fcckw\u00e4rts-Geschwindigkeit:
|
||||
loopbackCommAdapterPanel.label_operatingTime.text=Operationsdauer
|
||||
loopbackCommAdapterPanel.label_orientationAngle.text=Orientierung:
|
||||
loopbackCommAdapterPanel.label_pauseVehicle.text=Fahrzeug anhalten:
|
||||
loopbackCommAdapterPanel.label_position.text=Position:
|
||||
loopbackCommAdapterPanel.label_precisePosition.text=Exakte Position:
|
||||
loopbackCommAdapterPanel.label_propertyKey.text = Schl\u00fcssel:
|
||||
loopbackCommAdapterPanel.label_state.text=Zustand:
|
||||
loopbackCommAdapterPanel.panel_adapterStatus.border.title=Adapterzustand
|
||||
loopbackCommAdapterPanel.panel_commandProcessing.border.title=Kommandoverarbeitung
|
||||
loopbackCommAdapterPanel.panel_eventDispatching.title=Event-Versand
|
||||
loopbackCommAdapterPanel.panel_loadHandlingDevice.border.title=Lastaufnahmemittel
|
||||
loopbackCommAdapterPanel.panel_vehicleProperties.border.title=Fahrzeugeigenschaften
|
||||
loopbackCommAdapterPanel.panel_vehicleProperty.border.title = Fahrzeug-Property
|
||||
loopbackCommAdapterPanel.panel_vehicleStatus.border.title=Aktuelle Position
|
||||
loopbackCommAdapterPanel.radioButton_removeProperty.text=Property l\u00f6schen
|
||||
loopbackCommAdapterPanel.radioButton_setProperty.text=Diesen Wert setzen:
|
||||
loopbackCommAdapterPanel.textArea_precisePosition.positionNotSetPlaceholder=-
|
||||
loopbackCommAdapterPanel.textField_orientationAngle.angleNotSetPlaceholder=-
|
||||
loopbackCommunicationAdapterDescription.description=Loopback-Treiber (virtuelles Fahrzeug)
|
||||
|
After Width: | Height: | Size: 957 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 679 B |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) --><svg height="48" id="svg2" inkscape:export-filename="/home/jimmac/Desktop/drive-harddisk.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:version="0.45" sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/actions" sodipodi:docname="document-save.svg" sodipodi:version="0.32" version="1.0" width="48" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<metadata>
|
||||
<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<cc:Work rdf:about="">
|
||||
<dc:title>Jakub Steiner, Lapo Calamandrei</dc:title>
|
||||
<dc:description></dc:description>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>hdd</rdf:li>
|
||||
<rdf:li>drive</rdf:li>
|
||||
<rdf:li>fixed</rdf:li>
|
||||
<rdf:li>media</rdf:li>
|
||||
<rdf:li>hard</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<dc:publisher>
|
||||
<cc:Agent rdf:about="http://www.openclipart.org/">
|
||||
<dc:title>Open Clip Art Library, Source: GNOME Icon Theme, Source: GNOME Icon Theme, Source: GNOME Icon Theme, Source: GNOME Icon Theme</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner, Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner, Lapo Calamandrei</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<dc:date></dc:date>
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/"/>
|
||||
<dc:language>en</dc:language>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs4">
|
||||
<linearGradient id="linearGradient7781" inkscape:collect="always">
|
||||
<stop id="stop7783" offset="0" style="stop-color:#ffffff;stop-opacity:1;"/>
|
||||
<stop id="stop7785" offset="1" style="stop-color:#ffffff;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient6715" inkscape:collect="always">
|
||||
<stop id="stop6717" offset="0" style="stop-color:#000000;stop-opacity:1;"/>
|
||||
<stop id="stop6719" offset="1" style="stop-color:#000000;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient6549">
|
||||
<stop id="stop6551" offset="0" style="stop-color:#8ae234;stop-opacity:1"/>
|
||||
<stop id="stop6553" offset="1" style="stop-color:#73d216;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2916" inkscape:collect="always">
|
||||
<stop id="stop2918" offset="0" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop2920" offset="1" style="stop-color:white;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2902" inkscape:collect="always">
|
||||
<stop id="stop2905" offset="0" style="stop-color:black;stop-opacity:1;"/>
|
||||
<stop id="stop2907" offset="1" style="stop-color:black;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2986" inkscape:collect="always">
|
||||
<stop id="stop2988" offset="0" style="stop-color:black;stop-opacity:1;"/>
|
||||
<stop id="stop2990" offset="1" style="stop-color:black;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2967" inkscape:collect="always">
|
||||
<stop id="stop2969" offset="0" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop2971" offset="1" style="stop-color:white;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2064">
|
||||
<stop id="stop2066" offset="0" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop2070" offset="0.5" style="stop-color:#555753;stop-opacity:0.60000002;"/>
|
||||
<stop id="stop2068" offset="1" style="stop-color:#555753;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient9641">
|
||||
<stop id="stop9643" offset="0" style="stop-color:white;stop-opacity:1"/>
|
||||
<stop id="stop9645" offset="1" style="stop-color:#888a85;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient9633">
|
||||
<stop id="stop9635" offset="0" style="stop-color:#eeeeec;stop-opacity:1"/>
|
||||
<stop id="stop9639" offset="1" style="stop-color:#888a85;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient9613">
|
||||
<stop id="stop9615" offset="0" style="stop-color:white;stop-opacity:1"/>
|
||||
<stop id="stop9619" offset="0.5" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop9617" offset="1" style="stop-color:#cccfca;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient8710">
|
||||
<stop id="stop8712" offset="0" style="stop-color:black;stop-opacity:1;"/>
|
||||
<stop id="stop8714" offset="1" style="stop-color:white;stop-opacity:1;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient8631">
|
||||
<stop id="stop8633" offset="0" style="stop-color:#eeeeec;stop-opacity:1"/>
|
||||
<stop id="stop8637" offset="0.2" style="stop-color:#eeeeec;stop-opacity:1;"/>
|
||||
<stop id="stop8635" offset="1" style="stop-color:#babdb6;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient8625">
|
||||
<stop id="stop8627" offset="0" style="stop-color:white;stop-opacity:1"/>
|
||||
<stop id="stop8629" offset="1" style="stop-color:#babdb6;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient8613">
|
||||
<stop id="stop8615" offset="0" style="stop-color:#babdb6;stop-opacity:1"/>
|
||||
<stop id="stop8617" offset="1" style="stop-color:#2e3436;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5740">
|
||||
<stop id="stop5742" offset="0" style="stop-color:#d0d0cb;stop-opacity:1;"/>
|
||||
<stop id="stop5744" offset="1" style="stop-color:#babdb6;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5690">
|
||||
<stop id="stop5692" offset="0" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop5694" offset="1" style="stop-color:#888a85;stop-opacity:0.59848487"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2899">
|
||||
<stop id="stop2901" offset="0" style="stop-color:#555753;stop-opacity:1"/>
|
||||
<stop id="stop2903" offset="1" style="stop-color:#2e3436;stop-opacity:1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient3468">
|
||||
<stop id="stop3470" offset="0" style="stop-color:#fdfdfc;stop-opacity:1"/>
|
||||
<stop id="stop3472" offset="1" style="stop-color:white;stop-opacity:0.37121212"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2909">
|
||||
<stop id="stop2911" offset="0" style="stop-color:white;stop-opacity:0;"/>
|
||||
<stop id="stop2917" offset="0.5" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop2913" offset="1" style="stop-color:white;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2839">
|
||||
<stop id="stop2841" offset="0" style="stop-color:white;stop-opacity:0.25773194;"/>
|
||||
<stop id="stop2847" offset="0.5472973" style="stop-color:white;stop-opacity:1;"/>
|
||||
<stop id="stop2849" offset="0.66243607" style="stop-color:white;stop-opacity:0.24705882;"/>
|
||||
<stop id="stop2851" offset="0.875" style="stop-color:white;stop-opacity:0.83505154;"/>
|
||||
<stop id="stop2843" offset="1" style="stop-color:white;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2900">
|
||||
<stop id="stop2902" offset="0" style="stop-color:black;stop-opacity:0;"/>
|
||||
<stop id="stop2908" offset="0.5" style="stop-color:black;stop-opacity:1;"/>
|
||||
<stop id="stop2904" offset="1" style="stop-color:black;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient2886" inkscape:collect="always">
|
||||
<stop id="stop2888" offset="0" style="stop-color:black;stop-opacity:1;"/>
|
||||
<stop id="stop2890" offset="1" style="stop-color:black;stop-opacity:0;"/>
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(1,0,0,0.995556,0,1.068887)" gradientUnits="userSpaceOnUse" id="linearGradient3474" inkscape:collect="always" x1="24.748737" x2="24.998737" xlink:href="#linearGradient3468" y1="35.354588" y2="14.997767"/>
|
||||
<radialGradient cx="0" cy="17" fx="0" fy="17" gradientTransform="matrix(4.095822,0,0,3.101282,-9.53921,-94.5433)" gradientUnits="userSpaceOnUse" id="radialGradient4700" inkscape:collect="always" r="2" xlink:href="#linearGradient2886"/>
|
||||
<radialGradient cx="0" cy="17" fx="0" fy="17" gradientTransform="matrix(4.095822,0,0,3.101282,38.20996,-10.90025)" gradientUnits="userSpaceOnUse" id="radialGradient4702" inkscape:collect="always" r="2" xlink:href="#linearGradient2886"/>
|
||||
<linearGradient gradientTransform="matrix(2.047911,0,0,2.067521,1.347566,6.673675)" gradientUnits="userSpaceOnUse" id="linearGradient4704" inkscape:collect="always" x1="9.8994951" x2="9.8994951" xlink:href="#linearGradient2900" y1="20" y2="13.979153"/>
|
||||
<linearGradient gradientTransform="matrix(1,0,0,1.42294,10.5,-14.95703)" gradientUnits="userSpaceOnUse" id="linearGradient4711" inkscape:collect="always" x1="15.335379" x2="20.329321" xlink:href="#linearGradient2909" y1="33.06237" y2="36.37693"/>
|
||||
<linearGradient gradientTransform="matrix(1,0,0,1.42294,-0.875,-15.04578)" gradientUnits="userSpaceOnUse" id="linearGradient4713" inkscape:collect="always" x1="15.335379" x2="20.329321" xlink:href="#linearGradient2909" y1="33.06237" y2="36.37693"/>
|
||||
<linearGradient gradientTransform="matrix(0.459833,0,-0.391165,1.370105,40.62503,-13.29892)" gradientUnits="userSpaceOnUse" id="linearGradient4715" inkscape:collect="always" x1="15.335379" x2="20.329321" xlink:href="#linearGradient2909" y1="33.06237" y2="36.37693"/>
|
||||
<radialGradient cx="25.251999" cy="16.47991" fx="25.251999" fy="16.47991" gradientTransform="matrix(1.032991,-0.596398,0.575121,0.99614,-12.23456,16.55448)" gradientUnits="userSpaceOnUse" id="radialGradient5748" inkscape:collect="always" r="21.980215" xlink:href="#linearGradient5740"/>
|
||||
<linearGradient gradientTransform="matrix(0.940224,0,0,0.931632,1.331811,6.401537)" gradientUnits="userSpaceOnUse" id="linearGradient5790" inkscape:collect="always" x1="18.048874" x2="22.211937" xlink:href="#linearGradient2064" y1="25.461344" y2="12.143078"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient5865" inkscape:collect="always" x1="24" x2="25.818018" xlink:href="#linearGradient8631" y1="36.638382" y2="6.8314762"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7658" inkscape:collect="always" x1="27.057796" x2="32.042896" xlink:href="#linearGradient2839" y1="12.669416" y2="31.219666"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient8603" inkscape:collect="always" x1="20.304037" x2="18.498415" xlink:href="#linearGradient5690" y1="24.035707" y2="40.647167"/>
|
||||
<radialGradient cx="7.5177727" cy="30.573555" fx="7.5177727" fy="30.573555" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8619" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient8613"/>
|
||||
<radialGradient cx="7.5191436" cy="30.304251" fx="7.5191436" fy="30.304251" gradientTransform="matrix(1.389748,0,0,1.348872,-2.91982,-10.63815)" gradientUnits="userSpaceOnUse" id="radialGradient8623" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient9613"/>
|
||||
<radialGradient cx="7.5336008" cy="30.307562" fx="7.5336008" fy="30.307562" gradientTransform="matrix(1.569487,0,0,1.523325,-4.288627,-15.92107)" gradientUnits="userSpaceOnUse" id="radialGradient8664" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient9633"/>
|
||||
<radialGradient cx="7.5177727" cy="30.573555" fx="7.5177727" fy="30.573555" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8666" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient8613"/>
|
||||
<radialGradient cx="7.4792061" cy="30.36071" fx="7.4792061" fy="30.36071" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8676" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient8625"/>
|
||||
<radialGradient cx="7.5177727" cy="30.573555" fx="7.5177727" fy="30.573555" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8678" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient8613"/>
|
||||
<radialGradient cx="7.4893188" cy="30.337601" fx="7.4893188" fy="30.337601" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8680" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient9641"/>
|
||||
<radialGradient cx="7.5177727" cy="30.573555" fx="7.5177727" fy="30.573555" gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)" gradientUnits="userSpaceOnUse" id="radialGradient8682" inkscape:collect="always" r="0.53125" xlink:href="#linearGradient8613"/>
|
||||
<linearGradient gradientTransform="translate(0,5)" gradientUnits="userSpaceOnUse" id="linearGradient8716" inkscape:collect="always" x1="40.617188" x2="40.710938" xlink:href="#linearGradient8710" y1="30.554688" y2="30.359375"/>
|
||||
<linearGradient gradientTransform="matrix(0.602867,-0.797841,0.797841,0.602867,-41.12611,49.62773)" gradientUnits="userSpaceOnUse" id="linearGradient9605" inkscape:collect="always" x1="40.617188" x2="40.710938" xlink:href="#linearGradient8710" y1="30.554688" y2="30.359375"/>
|
||||
<linearGradient gradientTransform="matrix(0.866025,-0.5,0.5,0.866025,-38.79233,12.403385)" gradientUnits="userSpaceOnUse" id="linearGradient9649" inkscape:collect="always" x1="40.617188" x2="40.710938" xlink:href="#linearGradient8710" y1="30.554688" y2="30.359375"/>
|
||||
<linearGradient gradientTransform="matrix(0.707107,0.527555,-0.707107,0.527555,29.0058,-19.09196)" gradientUnits="userSpaceOnUse" id="linearGradient9654" inkscape:collect="always" x1="40.617188" x2="40.710938" xlink:href="#linearGradient8710" y1="30.554688" y2="30.359375"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient2973" inkscape:collect="always" x1="12.5" x2="12.5" xlink:href="#linearGradient2967" y1="43.1875" y2="34.045513"/>
|
||||
<linearGradient gradientTransform="translate(0,50)" gradientUnits="userSpaceOnUse" id="linearGradient5655" inkscape:collect="always" x1="53.812813" x2="-2.8138931" xlink:href="#linearGradient2899" y1="43.573235" y2="35.500015"/>
|
||||
<linearGradient gradientTransform="translate(0,5)" gradientUnits="userSpaceOnUse" id="linearGradient2992" inkscape:collect="always" x1="21.9375" x2="21.9375" xlink:href="#linearGradient2986" y1="39" y2="37.995617"/>
|
||||
<linearGradient gradientTransform="translate(0,7)" gradientUnits="userSpaceOnUse" id="linearGradient2910" inkscape:collect="always" x1="22.101398" x2="22.971142" xlink:href="#linearGradient2902" y1="27.658131" y2="20.903238"/>
|
||||
<linearGradient gradientTransform="translate(0,7)" gradientUnits="userSpaceOnUse" id="linearGradient2922" inkscape:collect="always" x1="24.847851" x2="24.847851" xlink:href="#linearGradient2916" y1="28.908398" y2="25.757175"/>
|
||||
<radialGradient cx="16.5" cy="15" fx="16.5" fy="15" gradientTransform="matrix(1,0,0,0.5454545,0,6.8181818)" gradientUnits="userSpaceOnUse" id="radialGradient6752" inkscape:collect="always" r="5.5" xlink:href="#linearGradient6715"/>
|
||||
<linearGradient gradientTransform="matrix(1.4314406,0,0,1.4345912,0.332755,-5.7794018)" gradientUnits="userSpaceOnUse" id="linearGradient7822" inkscape:collect="always" x1="17.894716" x2="15.704281" xlink:href="#linearGradient6549" y1="14.069843" y2="4.725668"/>
|
||||
<linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7826" inkscape:collect="always" x1="23.5" x2="16.124319" xlink:href="#linearGradient7781" y1="17.0625" y2="17.0625"/>
|
||||
</defs>
|
||||
<sodipodi:namedview bordercolor="#666" borderlayer="true" borderopacity="0.36078431" gridempspacing="2" gridspacingx="0.5px" gridspacingy="0.5px" height="48px" id="base" inkscape:current-layer="layer1" inkscape:cx="25.082453" inkscape:cy="33.916599" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:grid-points="true" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:showpageshadow="false" inkscape:window-height="715" inkscape:window-width="872" inkscape:window-x="209" inkscape:window-y="285" inkscape:zoom="1" pagecolor="#ffffff" showborder="false" showgrid="false" showguides="false" width="48px">
|
||||
<sodipodi:guide id="guide2023" orientation="horizontal" position="12"/>
|
||||
<sodipodi:guide id="guide2025" orientation="horizontal" position="27.5"/>
|
||||
</sodipodi:namedview>
|
||||
<g id="layer1" inkscape:groupmode="layer" inkscape:label="Livello 1" style="display:inline">
|
||||
<g id="g3519" inkscape:export-filename="/home/lapo/Desktop/uhm.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" style="opacity:0.7" transform="matrix(1.030831,0,0,1.151147,-0.73609,-7.57431)">
|
||||
<rect height="12.405126" id="rect2884" style="opacity:1;fill:url(#radialGradient4700);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" transform="scale(-1,-1)" width="8.1916437" x="-9.5392103" y="-48.024086"/>
|
||||
<rect height="12.405126" id="rect2894" style="opacity:1;fill:url(#radialGradient4702);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" width="8.1916437" x="38.209965" y="35.618961"/>
|
||||
<rect height="12.405126" id="rect2898" style="opacity:1;fill:url(#linearGradient4704);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" width="28.670753" x="9.5392103" y="35.618961"/>
|
||||
</g>
|
||||
<g id="g5672" transform="translate(0,-43.99747)">
|
||||
<path d="M 4.5182287,80.500013 L 43.481768,80.500013 C 44.045867,80.500013 44.499997,80.954143 44.499997,81.518242 L 44.499997,84.481785 C 44.499997,85.797369 44.049766,87.500013 42.044268,87.500013 L 40.5,87.5 L 40.5,88.5 L 7.5,88.5 L 7.5,87.5 L 5.6432287,87.500013 C 4.3720234,87.500013 3.5000005,86.615386 3.5000005,85.244348 L 3.5000005,81.518242 C 3.5000005,80.954143 3.9541302,80.500013 4.5182287,80.500013 z " id="rect2010" sodipodi:nodetypes="ccccccccccccc" style="color:#000000;fill:url(#linearGradient5655);fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"/>
|
||||
<path d="M 4.59375,31.59375 L 4.59375,35.323493 C 4.59375,35.923112 4.9694005,36.428347 5.4800776,36.428347 L 42.426407,36.428347 C 42.938876,36.428347 43.40625,35.921112 43.40625,35.411881 L 43.40625,31.59375 L 4.59375,31.59375 z " id="path2076" sodipodi:nodetypes="ccccccc" style="opacity:0.1;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2973);stroke-width:0.99999988;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="translate(0,50)"/>
|
||||
<g id="g4706" style="opacity:0.5" transform="translate(0,50)">
|
||||
<path d="M 26.144738,32.088747 C 26.144738,32.088747 24.642136,37.622686 22.918563,38 C 22.918563,38 29.149941,37.874229 29.149941,37.874229 C 30.537013,37.556768 32.508699,32.088747 32.508699,32.088747 L 26.144738,32.088747 z " id="path2907" inkscape:export-filename="/home/lapo/Desktop/uhm.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:nodetypes="ccccc" style="opacity:0.10952382;fill:url(#linearGradient4711);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||
<path d="M 14.769738,32 C 14.769738,32 13.267136,37.533939 11.543563,37.911253 C 11.543563,37.911253 17.774941,37.785482 17.774941,37.785482 C 19.162013,37.468021 21.133699,32 21.133699,32 L 14.769738,32 z " id="path2892" inkscape:export-filename="/home/lapo/Desktop/uhm.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:nodetypes="ccccc" style="opacity:0.10952382;fill:url(#linearGradient4713);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||
<path d="M 34.886139,32 C 34.886139,32 32.673915,37.328458 31.777636,37.691761 C 31.777636,37.691761 34.677605,37.57066 34.677605,37.57066 C 35.402697,37.264987 37.8125,32 37.8125,32 L 34.886139,32 z " id="path2896" inkscape:export-filename="/home/lapo/Desktop/uhm.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:nodetypes="ccccc" style="opacity:0.10952382;fill:url(#linearGradient4715);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M 11.693127,15.498788 L 36.265693,15.498788 C 37.949863,15.498788 38.66221,15.616267 39.305712,17.883793 L 44.380203,35.764912 C 44.881227,37.530383 43.024355,38.500013 41.340185,38.500013 L 6.6186312,38.500013 C 4.7502232,38.500013 3.1292479,37.318596 3.578613,35.764912 L 8.8290448,17.611497 C 9.3973456,15.646592 10.008957,15.498788 11.693127,15.498788 z " id="rect1879" inkscape:export-filename="/home/lapo/Desktop/uhm.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:nodetypes="cczzcczzc" style="fill:url(#radialGradient5748);fill-opacity:1;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"/>
|
||||
<path d="M 11.6875,11 C 10.861258,11 10.40275,11.065232 10.125,11.25 C 9.8472503,11.434768 9.5847988,11.808525 9.3125,12.75 L 4.0625,30.875 C 3.8916752,31.465628 4.0939747,31.914316 4.5625,32.3125 C 5.0310253,32.710684 5.7975106,33.000001 6.625,33 L 41.34375,33 C 42.088405,33 42.882691,32.7518 43.375,32.375 C 43.867309,31.9982 44.106017,31.578923 43.90625,30.875 L 38.84375,13 C 38.534499,11.910283 38.220548,11.458908 37.90625,11.25 C 37.591952,11.041092 37.112699,11 36.28125,11 L 11.6875,11 z " id="path5806" inkscape:original="M 11.6875 10.5 C 10.00333 10.5 9.4120513 10.660095 8.84375 12.625 L 3.59375 30.75 C 3.1443849 32.303684 4.7565918 33.500002 6.625 33.5 L 41.34375 33.5 C 43.02792 33.5 44.876024 32.515471 44.375 30.75 L 39.3125 12.875 C 38.668998 10.607474 37.965419 10.5 36.28125 10.5 L 11.6875 10.5 z " inkscape:radius="-0.5" sodipodi:type="inkscape:offset" style="opacity:0.46240599;fill:url(#linearGradient7658);fill-opacity:1;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;display:inline" transform="translate(0,5)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8621" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8623);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(-2.628602,0,0,1.777765,27.79309,-18.77739)"/>
|
||||
<path d="M 16.110953,17.552805 C 15.537372,17.552805 15.082583,17.984626 15.082583,18.542664 L 14.14236,21.773465 C 11.282398,23.049979 9.5000048,24.872538 9.5000048,26.897441 C 9.5000048,30.754398 15.979029,33.88468 23.985327,33.884681 C 31.991623,33.884681 38.500032,30.754397 38.500031,26.897441 C 38.500031,24.858407 36.66444,23.022053 33.76953,21.744352 L 32.829306,18.542664 C 32.829306,17.984626 32.374518,17.552805 31.800936,17.552805 L 16.110953,17.552805 z " id="path2784" sodipodi:nodetypes="cccssscccc" style="fill:none;fill-opacity:1;stroke:url(#linearGradient5790);stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
|
||||
<path d="M 11.6875,16.500005 C 10.884376,16.500005 10.590332,16.570515 10.46875,16.655561 C 10.347168,16.740606 10.111043,17.057681 9.78125,17.962228 L 4.53125,36.100014 C 4.3975296,36.466779 4.4764233,36.633879 4.84375,36.940014 C 5.2110767,37.24615 5.910443,37.500014 6.625,37.500015 L 41.34375,37.500015 C 41.983543,37.500015 42.737095,37.262061 43.125,36.971125 C 43.512905,36.68019 43.613311,36.588316 43.4375,36.100014 L 38.375,18.242228 C 37.997794,17.194568 37.69292,16.802931 37.53125,16.686672 C 37.36958,16.570413 37.087539,16.500005 36.28125,16.500005 L 11.6875,16.500005 z " id="path3394" sodipodi:nodetypes="csccsccsccscc" style="fill:none;fill-opacity:1;stroke:url(#linearGradient3474);stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;display:inline"/>
|
||||
<g id="g5657" style="opacity:0.3028571" transform="translate(7,4)">
|
||||
<rect height="1.9999924" id="rect5641" rx="0.75130093" ry="0.74712253" style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.00000024;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="14.000004" x="18.499996" y="35.500008"/>
|
||||
<rect height="1" id="rect5645" style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="1" x="19" y="36"/>
|
||||
<rect height="1" id="rect5647" style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="1" x="22" y="36"/>
|
||||
<rect height="1" id="rect5649" style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="1" x="24" y="36"/>
|
||||
<rect height="1" id="rect5651" style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="1" x="26" y="36"/>
|
||||
<rect height="1" id="rect5653" style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="2" x="29" y="36"/>
|
||||
</g>
|
||||
<path d="M 16.125,13 C 15.762388,13 15.53125,13.214848 15.53125,13.53125 C 15.537172,13.572706 15.537172,13.614794 15.53125,13.65625 L 14.59375,16.90625 C 14.55648,17.032564 14.464823,17.135678 14.34375,17.1875 C 12.953848,17.807869 11.845241,18.565737 11.09375,19.375 C 10.342259,20.184263 9.9375,21.02448 9.9375,21.90625 C 9.9375,23.586705 11.392464,25.21545 13.9375,26.4375 C 16.482536,27.65955 20.054107,28.4375 24,28.4375 C 27.945892,28.4375 31.517463,27.65955 34.0625,26.4375 C 36.607537,25.21545 38.0625,23.586705 38.0625,21.90625 C 38.0625,21.018499 37.668724,20.159037 36.90625,19.34375 C 36.143776,18.528463 35.000895,17.777309 33.59375,17.15625 C 33.472677,17.104428 33.38102,17.001314 33.34375,16.875 L 32.40625,13.65625 C 32.400328,13.614794 32.400328,13.572706 32.40625,13.53125 C 32.406249,13.214846 32.175114,13 31.8125,13 L 16.125,13 z " id="path5857" inkscape:original="M 16.125 12.5625 C 15.55142 12.5625 15.09375 12.973212 15.09375 13.53125 L 14.15625 16.78125 C 11.296288 18.057765 9.5 19.881347 9.5 21.90625 C 9.5 25.763206 15.993702 28.874999 24 28.875 C 32.006296 28.874999 38.500001 25.763206 38.5 21.90625 C 38.5 19.867215 36.67616 18.027701 33.78125 16.75 L 32.84375 13.53125 C 32.843748 12.973212 32.386082 12.5625 31.8125 12.5625 L 16.125 12.5625 z " inkscape:radius="-0.44194174" sodipodi:type="inkscape:offset" style="fill:url(#linearGradient5865);fill-opacity:1;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" transform="translate(0,5)"/>
|
||||
<path d="M 24.748736 25.107418 A 7.7781744 4.2868347 0 1 1 9.1923876,25.107418 A 7.7781744 4.2868347 0 1 1 24.748736 25.107418 z" id="path8595" sodipodi:cx="16.970562" sodipodi:cy="25.107418" sodipodi:rx="7.7781744" sodipodi:ry="4.2868347" sodipodi:type="arc" style="opacity:0.9;color:#000000;fill:#000000;fill-opacity:0.05303028;fill-rule:nonzero;stroke:url(#linearGradient8603);stroke-width:2.52015233;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(0.449978,0,0,0.349909,16.36363,17.21469)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8611" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8619);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(1.411772,0,0,0.969697,-3.014767,5.848485)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8660" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8664);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.46259445;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(-2.628602,0,0,1.777765,60.79309,-18.77739)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8662" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8666);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(1.411772,0,0,0.969697,29.98523,5.848485)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8668" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8676);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(-2.628602,0,0,1.777765,31.79309,-35.77739)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8670" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8678);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(1.411772,0,0,0.969697,0.985233,-11.15152)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8672" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8680);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(-2.628602,0,0,1.777765,56.3029,-35.77739)"/>
|
||||
<path d="M 8.15625 30.578125 A 0.53125 0.515625 0 1 1 7.09375,30.578125 A 0.53125 0.515625 0 1 1 8.15625 30.578125 z" id="path8674" sodipodi:cx="7.625" sodipodi:cy="30.578125" sodipodi:rx="0.53125" sodipodi:ry="0.515625" sodipodi:type="arc" style="opacity:1;color:#000000;fill:url(#radialGradient8682);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" transform="matrix(1.411772,0,0,0.969697,25.49504,-11.15152)"/>
|
||||
<path d="M 40.328109,35.261401 L 41.203108,35.691733" id="path8700" style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient8716);stroke-width:0.29999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||
<path d="M 7.330186,35.695906 L 8.201031,35.257228" id="path9603" style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9605);stroke-width:0.29999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"/>
|
||||
<path d="M 11.263531,18.446473 L 12.236468,18.381651" id="path9647" style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9649);stroke-width:0.29999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"/>
|
||||
<path d="M 36.124038,18.147874 L 36.438465,18.836508" id="path9652" style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9654);stroke-width:0.29999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"/>
|
||||
<rect height="1" id="rect2984" style="opacity:0.12000002;color:#000000;fill:url(#linearGradient2992);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.68183619;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" width="32.03125" x="8" y="43"/>
|
||||
<path d="M 10.460155,20.082355 L 6.8513979,32.675762 C 8.2982685,33.375511 10.625,34.167061 10.429825,36.533131 L 37.299883,36.533131 C 37.869398,34.640915 39.875,33.375 41.34614,33.25 L 37.498106,20.082355 L 32.350135,17.523347 L 14.318912,17.523347 L 10.460155,20.082355 z " id="path1997" sodipodi:nodetypes="ccccccccc" style="opacity:0.12000002;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2910);stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"/>
|
||||
<path d="M 7.9763979,32.050762 C 9.4232685,32.750511 11.15533,33.484003 11.402097,35.408131 L 36.857941,35.408131 C 37.427456,33.515915 38.875,32.5 40.34614,32.375 L 7.9763979,32.050762 z " id="path2912" sodipodi:nodetypes="ccccc" style="opacity:0.83428572;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2922);stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"/>
|
||||
<path d="M 22 15 A 5.5 3 0 1 1 11,15 A 5.5 3 0 1 1 22 15 z" id="path6723" sodipodi:cx="16.5" sodipodi:cy="15" sodipodi:rx="5.5" sodipodi:ry="3" sodipodi:type="arc" style="opacity:0.2;fill:url(#radialGradient6752);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" transform="matrix(2.1471606,0,0,1.4314409,-11.580953,1.2105393)"/>
|
||||
<g id="g7817" transform="translate(0,-1)">
|
||||
<path d="M 29.5,1.5 L 18.5,1.5 L 18.5,13.5 L 12.5,13.5 L 24,26.5 L 35.5,13.5 L 29.5,13.5 L 29.5,1.5 z " id="path6526" sodipodi:nodetypes="cccccccc" style="fill:url(#linearGradient7822);fill-opacity:1;stroke:#4e9a06;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"/>
|
||||
<path d="M 28.5,2.5 L 19.5,2.5 L 19.5,13.5 C 19.500004,14.052286 19.052286,14.500004 18.5,14.5 L 14.71875,14.5 L 24,25 L 33.28125,14.5 L 29.5,14.5 C 28.947714,14.500004 28.499996,14.052286 28.5,13.5 L 28.5,2.5 z " id="path7769" sodipodi:nodetypes="cccccccccc" style="opacity:0.6;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;display:inline"/>
|
||||
<path d="M 19,2 L 19,13.5 C 18.999972,13.776131 18.776131,13.999972 18.5,14 L 13.625,14 L 24,25.71875 L 24,2 L 19,2 z " id="path7776" sodipodi:nodetypes="ccccccc" style="opacity:0.5;fill:url(#linearGradient7826);fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,158 @@
|
||||
// SPDX-FileCopyrightText: The openTCS Authors
|
||||
// SPDX-License-Identifier: MIT
|
||||
package org.opentcs.virtualvehicle;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentcs.data.model.Vehicle;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link VelocityController}.
|
||||
*/
|
||||
class VelocityControllerTest {
|
||||
|
||||
private static final int MAX_DECEL = -1000;
|
||||
private static final int MAX_ACCEL = 1000;
|
||||
private static final int MAX_REV_VELO = -500;
|
||||
private static final int MAX_FWD_VELO = 500;
|
||||
|
||||
private static final long WAY_LENGTH = 5000;
|
||||
private static final int MAX_VELO = 500;
|
||||
private static final String POINT_NAME = "Destination_Point";
|
||||
|
||||
private VelocityController controller;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
controller = new VelocityController(MAX_DECEL, MAX_ACCEL, MAX_REV_VELO, MAX_FWD_VELO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialControllerHasNoWayEntries() {
|
||||
assertFalse(controller.hasWayEntries());
|
||||
assertNull(controller.getCurrentWayEntry());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAddingNullWayEntry() {
|
||||
assertThrows(NullPointerException.class, () -> controller.addWayEntry(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwOnAdvancingWithNegativeTime() {
|
||||
assertThrows(IllegalArgumentException.class, () -> controller.advanceTime(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void advanceTimeAdvancesTime() {
|
||||
long timeBefore = controller.getCurrentTime();
|
||||
|
||||
controller.advanceTime(5);
|
||||
|
||||
assertThat(controller.getCurrentTime(), is(timeBefore + 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void vehicleDoesNotChangePositionWhilePaused() {
|
||||
VelocityController.WayEntry wayEntry
|
||||
= new VelocityController.WayEntry(
|
||||
WAY_LENGTH,
|
||||
MAX_VELO,
|
||||
POINT_NAME,
|
||||
Vehicle.Orientation.FORWARD
|
||||
);
|
||||
controller.addWayEntry(wayEntry);
|
||||
controller.setVehiclePaused(true);
|
||||
|
||||
long posBefore = controller.getCurrentPosition();
|
||||
|
||||
controller.advanceTime(5);
|
||||
|
||||
assertThat(controller.getCurrentPosition(), is(posBefore));
|
||||
}
|
||||
|
||||
@Test
|
||||
void processWayEntriesInGivenOrder() {
|
||||
controller = new VelocityController(MAX_DECEL, 1000, MAX_REV_VELO, 500);
|
||||
|
||||
VelocityController.WayEntry firstEntry
|
||||
= new VelocityController.WayEntry(1, MAX_VELO, POINT_NAME, Vehicle.Orientation.FORWARD);
|
||||
VelocityController.WayEntry secondEntry
|
||||
= new VelocityController.WayEntry(10000, MAX_VELO, POINT_NAME, Vehicle.Orientation.FORWARD);
|
||||
controller.addWayEntry(firstEntry);
|
||||
controller.addWayEntry(secondEntry);
|
||||
|
||||
assertThat(controller.getCurrentWayEntry(), is(sameInstance(firstEntry)));
|
||||
assertSame(firstEntry, controller.getCurrentWayEntry());
|
||||
|
||||
controller.advanceTime(100);
|
||||
|
||||
assertThat(controller.getCurrentWayEntry(), is(sameInstance(secondEntry)));
|
||||
assertSame(secondEntry, controller.getCurrentWayEntry());
|
||||
}
|
||||
|
||||
@Test
|
||||
void accelerateToMaxVelocityLimitedByController() {
|
||||
final int maxFwdVelocity = 500; // mm/s
|
||||
final int maxAcceleration = 250; // mm/s^2
|
||||
controller = new VelocityController(MAX_DECEL, maxAcceleration, MAX_REV_VELO, maxFwdVelocity);
|
||||
|
||||
// Way point with enough length to reach the maximum velocity and with a higher velocity limit
|
||||
// than the vehicle's own maximum velocity.
|
||||
VelocityController.WayEntry wayEntry
|
||||
= new VelocityController.WayEntry(
|
||||
100000,
|
||||
2 * maxFwdVelocity,
|
||||
POINT_NAME,
|
||||
Vehicle.Orientation.FORWARD
|
||||
);
|
||||
controller.addWayEntry(wayEntry);
|
||||
|
||||
controller.advanceTime(1000);
|
||||
|
||||
// Reach 250 mm/s in 1s:
|
||||
assertThat(controller.getCurrentVelocity(), is(250));
|
||||
|
||||
controller.advanceTime(1000);
|
||||
|
||||
// Reach max. velocity of 500 mm/s in 2s:
|
||||
assertThat(controller.getCurrentVelocity(), is(500));
|
||||
|
||||
controller.advanceTime(1000);
|
||||
|
||||
// Stay at max velocity:
|
||||
assertThat(controller.getCurrentVelocity(), is(500));
|
||||
}
|
||||
|
||||
@Test
|
||||
void accelerateToMaxVelocityLimitedByWayEntry() {
|
||||
final int maxFwdVelocity = 500; // mm/s
|
||||
final int maxAcceleration = 500; // mm/s^2
|
||||
controller = new VelocityController(MAX_DECEL, maxAcceleration, MAX_REV_VELO, maxFwdVelocity);
|
||||
|
||||
// Way point with a velocity limit less than the vehicle's own maximum velocity.
|
||||
VelocityController.WayEntry wayEntry
|
||||
= new VelocityController.WayEntry(
|
||||
10000,
|
||||
250,
|
||||
POINT_NAME,
|
||||
Vehicle.Orientation.FORWARD
|
||||
);
|
||||
controller.addWayEntry(wayEntry);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
controller.advanceTime(100);
|
||||
}
|
||||
|
||||
// Velocity could be 500 mm/s after one second, but should be limited to 250 mm/s.
|
||||
assertThat(controller.getCurrentVelocity(), is(250));
|
||||
}
|
||||
}
|
||||