Martin Kunz 5 years ago
commit
5e20a467ae
23 changed files with 1405 additions and 0 deletions
  1. 189 0
      .gitignore
  2. 16 0
      .idea/compiler.xml
  3. 16 0
      .idea/misc.xml
  4. 8 0
      .idea/modules.xml
  5. 6 0
      .idea/vcs.xml
  6. 23 0
      assembly.xml
  7. 40 0
      pickorplaceswing.iml
  8. 348 0
      pom.xml
  9. 25 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/Activator.java
  10. 61 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeContribution.java
  11. 52 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeService.java
  12. 25 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeView.java
  13. 60 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeContribution.java
  14. 49 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeService.java
  15. 24 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeView.java
  16. 163 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeContribution.java
  17. 46 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeService.java
  18. 109 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeView.java
  19. 44 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/Style.java
  20. 25 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/TemplateType.java
  21. 24 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/V3Style.java
  22. 24 0
      src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/V5Style.java
  23. 28 0
      src/main/resources/META-INF/LICENSE

+ 189 - 0
.gitignore

@@ -0,0 +1,189 @@
+
+# Created by https://www.gitignore.io/api/osx,java,linux,windows,intellij,maven
+# Edit at https://www.gitignore.io/?templates=osx,java,linux,windows,intellij,maven
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Intellij Patch ###
+# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
+
+# *.iml
+# modules.xml
+# .idea/misc.xml
+# *.ipr
+
+# Sonarlint plugin
+.idea/sonarlint
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+### OSX ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### Windows ###
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# End of https://www.gitignore.io/api/osx,java,linux,windows,intellij,maven

+ 16 - 0
.idea/compiler.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="pickorplaceswing" />
+      </profile>
+    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="pickorplaceswing" target="1.8" />
+    </bytecodeTargetLevel>
+  </component>
+</project>

+ 16 - 0
.idea/misc.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="FrameworkDetectionExcludesConfiguration">
+    <file type="Osmorc" url="file://$PROJECT_DIR$" />
+  </component>
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/pickorplaceswing.iml" filepath="$PROJECT_DIR$/pickorplaceswing.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 23 - 0
assembly.xml

@@ -0,0 +1,23 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
+    <id>sources</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>.</directory>
+            <includes>
+                <include>pom.xml</include>
+                <include>assembly.xml</include>
+            </includes>
+            <useDefaultExcludes>true</useDefaultExcludes>
+        </fileSet>
+        <fileSet>
+            <directory>src</directory>
+            <useDefaultExcludes>true</useDefaultExcludes>
+        </fileSet>
+    </fileSets>
+</assembly>

+ 40 - 0
pickorplaceswing.iml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="ExternalSystem" externalSystem="Maven" />
+  <component name="FacetManager">
+    <facet type="Osmorc" name="OSGi">
+      <configuration manifestGenerationMode="OsmorcControlled" manifestLocation="" jarfileLocation="urweb-1.0-SNAPSHOT.jar" outputPathType="CompilerOutputPath" bndFileLocation="" bundlorFileLocation="" bundleActivator="com.ur.urcap.examples.pickorplaceswing.Activator" bundleSymbolicName="at.acdp.urweb" bundleVersion="1.0.0.SNAPSHOT" ignoreFilePattern="" useProjectDefaultManifestFileLocation="true" alwaysRebuildBundleJAR="false" doNotSynchronizeWithMaven="false">
+        <additionalProperties>
+          <property key="Bundle-Category" value="URCap" />
+          <property key="Bundle-Vendor" value="cdp" />
+          <property key="Bundle-ContactAddress" value="Seestadtstraße 27/10 1220 Wien" />
+          <property key="Bundle-Copyright" value="Copyright (C) 2018 Center for Digital Production GmbH" />
+          <property key="Bundle-LicenseType" value="Commercial" />
+          <property key="Bundle-Description" value="urweb description" />
+          <property key="Import-Package" value="com.ur.urcap.api*;version=&quot;[1.3.0,2.0.0)&quot;,*" />
+          <property key="Bundle-Name" value="urweb" />
+          <property key="Include-Resource" value="META-INF/LICENSE=$MODULE_DIR$/src/main/resources/META-INF/LICENSE" />
+        </additionalProperties>
+        <additionalJARContents />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Maven: org.osgi:org.osgi.core:4.3.0" level="project" />
+    <orderEntry type="library" scope="PROVIDED" name="Maven: com.ur.urcap:api:1.3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.nanohttpd:nanohttpd:2.3.2-SNAPSHOT" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.3.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.0.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.1.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.3.1" level="project" />
+  </component>
+</module>

+ 348 - 0
pom.xml

@@ -0,0 +1,348 @@
+<?xml version="1.0"?>
+<project
+		xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>at.acdp.urweb</groupId>
+	<artifactId>urweb</artifactId>
+	<version>1.0-SNAPSHOT</version>
+	<name>urweb</name>
+	<packaging>bundle</packaging>
+
+	<properties>
+
+		<!--********************************************************************-->
+		<!--   Note: Update this section with relevant meta data                -->
+		<!--         that comes along with your URCap                           -->
+		<!--********************************************************************-->
+		<!--******************* BEGINNING OF URCAP META DATA *******************-->
+		<urcap.symbolicname>at.acdp.urweb</urcap.symbolicname>
+		<urcap.vendor>cdp</urcap.vendor>
+		<urcap.contactAddress>Seestadtstraße 27/10 1220 Wien</urcap.contactAddress>
+		<urcap.copyright>Copyright (C) 2018 Center for Digital Production GmbH</urcap.copyright>
+		<urcap.description>urweb description</urcap.description>
+		<urcap.licenseType>Commercial</urcap.licenseType>
+		<!--********************** END OF URCAP META DATA **********************-->
+		<!--********************************************************************-->
+
+		<!-- Host, username and password of the robot to be used when running "mvn install -Premote" -->
+		<urcap.install.host></urcap.install.host>
+		<urcap.install.username>root</urcap.install.username>
+		<urcap.install.password>easybot</urcap.install.password>
+
+		<!--Install path for the UR Sim-->
+		<ursim.home></ursim.home>
+
+		<!--Host and standard user/password for UR Sim running in a VM-->
+		<ursimvm.install.host></ursimvm.install.host>
+		<ursimvm.install.username>ur</ursimvm.install.username>
+		<ursimvm.install.password>easybot</ursimvm.install.password>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.6.0</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>3.1.0</version>
+				<configuration>
+					<archive>
+						<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<artifactId>maven-resources-plugin</artifactId>
+				<version>3.1.0</version>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>4.1.0</version>
+				<extensions>true</extensions>
+				<executions>
+					<execution>
+						<id>bundle-manifest</id>
+						<phase>process-classes</phase>
+						<goals>
+							<goal>manifest</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<instructions>
+						<!--********** DO NOT MODIFY THE ENTRIES OF THIS SECTION **********-->
+						<Bundle-Category>URCap</Bundle-Category>
+						<Bundle-Activator>com.ur.urcap.examples.pickorplaceswing.Activator</Bundle-Activator>
+						<Bundle-Vendor>${urcap.vendor}</Bundle-Vendor>
+						<Bundle-ContactAddress>${urcap.contactAddress}</Bundle-ContactAddress>
+						<Bundle-Copyright>${urcap.copyright}</Bundle-Copyright>
+						<Bundle-LicenseType>${urcap.licenseType}</Bundle-LicenseType>
+						<Bundle-Description>${urcap.description}</Bundle-Description>
+						<!--***************************************************************-->
+						<Import-Package>
+							com.ur.urcap.api*;version="[1.3.0,2.0.0)",
+							*
+						</Import-Package>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-antrun-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>server-copy</id>
+						<goals>
+							<goal>run</goal>
+						</goals>
+						<phase>install</phase>
+						<configuration>
+							<tasks>
+								<echo message="Pushing to host..." />
+								<scp file="target/${project.build.finalName}.jar" port="2222" trust="true"
+									 todir="ur:easybot@127.0.0.1:/home/ur"/>
+							</tasks>
+						</configuration>
+					</execution>
+				</executions>
+				<dependencies>
+					<dependency>
+						<groupId>org.apache.ant</groupId>
+						<artifactId>ant-jsch</artifactId>
+						<version>1.10.5</version>
+					</dependency>
+					<dependency>
+						<groupId>com.jcraft</groupId>
+						<artifactId>jsch</artifactId>
+						<version>0.1.54</version>
+					</dependency>
+					<dependency>
+						<groupId>commons-net</groupId>
+						<artifactId>commons-net</artifactId>
+						<version>3.6</version>
+					</dependency>
+					<dependency>
+						<groupId>ant</groupId>
+						<artifactId>ant-commons-net</artifactId>
+						<version>1.6.5</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+
+			<!--<plugin>-->
+				<!--<groupId>org.codehaus.mojo</groupId>-->
+				<!--<artifactId>exec-maven-plugin</artifactId>-->
+				<!--<version>1.1</version>-->
+				<!--<executions>-->
+					<!--&lt;!&ndash; generate URCap package after compiling &ndash;&gt;-->
+					<!--<execution>-->
+						<!--<id>package-urcap</id>-->
+						<!--<phase>package</phase>-->
+						<!--<goals>-->
+							<!--<goal>exec</goal>-->
+						<!--</goals>-->
+						<!--<configuration>-->
+							<!--<executable>cp</executable>-->
+							<!--<commandlineArgs>target/${project.build.finalName}.jar target/${project.build.finalName}.urcap</commandlineArgs>-->
+							<!--<workingDirectory>.</workingDirectory>-->
+						<!--</configuration>-->
+					<!--</execution>-->
+				<!--</executions>-->
+			<!--</plugin>-->
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptors>
+						<descriptor>assembly.xml</descriptor>
+					</descriptors>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+		<extensions>
+			<extension>
+				<groupId>org.apache.maven.wagon</groupId>
+				<artifactId>wagon-ssh</artifactId>
+				<version>3.2.0</version>
+			</extension>
+		</extensions>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.core</artifactId>
+			<version>4.3.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.ur.urcap</groupId>
+			<artifactId>api</artifactId>
+			<version>1.3.0</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<artifactId>nanohttpd</artifactId>
+			<groupId>org.nanohttpd</groupId>
+			<version>2.3.2-SNAPSHOT</version>
+		</dependency>
+
+		<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
+		<dependency>
+			<groupId>org.junit.jupiter</groupId>
+			<artifactId>junit-jupiter-api</artifactId>
+			<version>5.3.1</version>
+			<scope>test</scope>
+		</dependency>
+
+	</dependencies>
+
+	<profiles>
+		<profile>
+			<id>remote</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>1.1</version>
+						<executions>
+							<execution>
+								<id>remote-install-urcap</id>
+								<phase>install</phase>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+								<configuration>
+									<executable>sshpass</executable>
+									<commandlineArgs>-p ${urcap.install.password} scp -o StrictHostKeyChecking=no target/${project.build.finalName}.jar ${urcap.install.username}@${urcap.install.host}:/root/.urcaps/${urcap.symbolicname}.jar</commandlineArgs>
+									<workingDirectory>.</workingDirectory>
+								</configuration>
+							</execution>
+							<execution>
+								<id>remote-restart-ui</id>
+								<phase>install</phase>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+								<configuration>
+									<executable>sshpass</executable>
+									<commandlineArgs>-p ${urcap.install.password} ssh ${urcap.install.username}@${urcap.install.host} pkill java</commandlineArgs>
+									<workingDirectory>.</workingDirectory>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>local</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>1.1</version>
+						<executions>
+							<execution>
+								<id>local-install-urcap</id>
+								<phase>install</phase>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+								<configuration>
+									<executable>cp</executable>
+									<commandlineArgs>target/${project.build.finalName}.jar ${user.home}/.urcaps/${urcap.symbolicname}.jar</commandlineArgs>
+									<workingDirectory>.</workingDirectory>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>ursim</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>1.1</version>
+						<executions>
+							<execution>
+								<id>ursim-install-urcap</id>
+								<phase>install</phase>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+								<configuration>
+									<executable>cp</executable>
+									<commandlineArgs>target/${project.build.finalName}.jar ${ursim.home}/.urcaps/${urcap.symbolicname}.jar</commandlineArgs>
+									<workingDirectory>.</workingDirectory>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>ursimvm</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>1.1</version>
+						<executions>
+							<execution>
+								<id>ursimvm-install-urcap</id>
+								<phase>install</phase>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+								<configuration>
+									<executable>sshpass</executable>
+									<commandlineArgs>-p ${ursimvm.install.password} scp -o StrictHostKeyChecking=no target/${project.build.finalName}.jar ${ursimvm.install.username}@${ursimvm.install.host}:/home/ur/ursim-current/.urcaps/${urcap.symbolicname}.jar</commandlineArgs>
+									<workingDirectory>.</workingDirectory>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+
+	<repositories>
+		<repository>
+			<id>sonatype-snapshots</id>
+			<url>https://oss.sonatype.org/content/repositories/snapshots</url>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+
+</project>

+ 25 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/Activator.java

@@ -0,0 +1,25 @@
+package com.ur.urcap.examples.pickorplaceswing;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeService;
+import com.ur.urcap.examples.pickorplaceswing.close.GripperCloseProgramNodeService;
+import com.ur.urcap.examples.pickorplaceswing.open.GripperOpenProgramNodeService;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.PickOrPlaceProgramNodeService;
+
+public class Activator implements BundleActivator {
+
+	@Override
+	public void start(final BundleContext context) throws Exception {
+		context.registerService(SwingProgramNodeService.class, new PickOrPlaceProgramNodeService(), null);
+		context.registerService(SwingProgramNodeService.class, new GripperOpenProgramNodeService(), null);
+		context.registerService(SwingProgramNodeService.class, new GripperCloseProgramNodeService(), null);
+	}
+
+	@Override
+	public void stop(BundleContext context) throws Exception {
+
+	}
+
+}

+ 61 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeContribution.java

@@ -0,0 +1,61 @@
+package com.ur.urcap.examples.pickorplaceswing.close;
+
+import com.ur.urcap.api.contribution.ProgramNodeContribution;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.domain.ProgramAPI;
+import com.ur.urcap.api.domain.program.ProgramModel;
+import com.ur.urcap.api.domain.program.nodes.ProgramNodeFactory;
+import com.ur.urcap.api.domain.program.structure.TreeNode;
+import com.ur.urcap.api.domain.program.structure.TreeStructureException;
+import com.ur.urcap.api.domain.script.ScriptWriter;
+
+public class GripperCloseProgramNodeContribution implements ProgramNodeContribution {
+
+	private final ProgramAPIProvider apiProvider;
+
+	GripperCloseProgramNodeContribution(ProgramAPIProvider apiProvider) {
+		this.apiProvider = apiProvider;
+		createSubtree();
+	}
+
+	@Override
+	public String getTitle() {
+		return "Gripper Close";
+	}
+
+	@Override
+	public void openView() {
+	}
+
+	@Override
+	public void closeView() {
+	}
+
+	@Override
+	public boolean isDefined() {
+		return true;
+	}
+
+	@Override
+	public void generateScript(ScriptWriter writer) {
+		// Place script for closing gripper here
+		writer.writeChildren();
+	}
+
+	private void createSubtree() {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+		ProgramNodeFactory nf = programModel.getProgramNodeFactory();
+		TreeNode root = programModel.getRootTreeNode(this);
+
+		try {
+			root.addChild(nf.createCommentNode().setComment("Add your nodes here"));
+			root.addChild(nf.createSetNode());
+			root.addChild(nf.createWaitNode());
+		} catch (TreeStructureException e) {
+			e.printStackTrace();
+			// See e.getMessage() for explanation
+		}
+	}
+
+}

+ 52 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeService.java

@@ -0,0 +1,52 @@
+package com.ur.urcap.examples.pickorplaceswing.close;
+
+import java.util.Locale;
+
+import com.ur.urcap.api.contribution.ViewAPIProvider;
+import com.ur.urcap.api.contribution.program.ContributionConfiguration;
+import com.ur.urcap.api.contribution.program.CreationContext;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeService;
+import com.ur.urcap.api.domain.SystemAPI;
+import com.ur.urcap.api.domain.data.DataModel;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.Style;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.V3Style;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.V5Style;
+
+public class GripperCloseProgramNodeService
+		implements SwingProgramNodeService<GripperCloseProgramNodeContribution, GripperCloseProgramNodeView> {
+
+	public GripperCloseProgramNodeService() {
+	}
+
+	@Override
+	public String getTitle(Locale locale) {
+		return "Gripper Close";
+	}
+
+	@Override
+	public String getId() {
+		return "GripperProgramNode";
+	}
+
+	@Override
+	public void configureContribution(ContributionConfiguration configuration) {
+		configuration.setDeprecated(false);
+		configuration.setUserInsertable(false);
+		configuration.setChildrenAllowed(true);
+	}
+
+	@Override
+	public GripperCloseProgramNodeView createView(ViewAPIProvider apiProvider) {
+		SystemAPI systemAPI = apiProvider.getSystemAPI();
+		Style style = systemAPI.getSoftwareVersion().getMajorVersion() >= 5 ? new V5Style() : new V3Style();
+		return new GripperCloseProgramNodeView(style);
+	}
+
+	@Override
+	public GripperCloseProgramNodeContribution createNode(ProgramAPIProvider apiProvider,
+			GripperCloseProgramNodeView view, DataModel model, CreationContext context) {
+		return new GripperCloseProgramNodeContribution(apiProvider);
+	}
+
+}

+ 25 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/close/GripperCloseProgramNodeView.java

@@ -0,0 +1,25 @@
+package com.ur.urcap.examples.pickorplaceswing.close;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+
+import com.ur.urcap.api.contribution.ContributionProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeView;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.Style;
+
+public class GripperCloseProgramNodeView implements SwingProgramNodeView<GripperCloseProgramNodeContribution> {
+
+	private final Style style;
+
+	GripperCloseProgramNodeView(Style style) {
+		this.style = style;
+	}
+
+	@Override
+	public void buildUI(JPanel panel, ContributionProvider<GripperCloseProgramNodeContribution> provider) {
+		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+		panel.add(style.createVerticalSpacing());
+		panel.add(style.createInfo("Closing of the gripper is specified in this subtree."));
+	}
+
+}

+ 60 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeContribution.java

@@ -0,0 +1,60 @@
+package com.ur.urcap.examples.pickorplaceswing.open;
+
+import com.ur.urcap.api.contribution.ProgramNodeContribution;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.domain.ProgramAPI;
+import com.ur.urcap.api.domain.program.ProgramModel;
+import com.ur.urcap.api.domain.program.nodes.ProgramNodeFactory;
+import com.ur.urcap.api.domain.program.structure.TreeNode;
+import com.ur.urcap.api.domain.program.structure.TreeStructureException;
+import com.ur.urcap.api.domain.script.ScriptWriter;
+
+public class GripperOpenProgramNodeContribution implements ProgramNodeContribution {
+	private final ProgramAPIProvider apiProvider;
+
+	GripperOpenProgramNodeContribution(ProgramAPIProvider apiProvider) {
+		this.apiProvider = apiProvider;
+		createSubtree();
+	}
+
+	@Override
+	public String getTitle() {
+		return "Gripper Open";
+	}
+
+	@Override
+	public void openView() {
+	}
+
+	@Override
+	public void closeView() {
+	}
+
+	@Override
+	public boolean isDefined() {
+		return true;
+	}
+
+	@Override
+	public void generateScript(ScriptWriter writer) {
+		// Place script for opening gripper here
+		writer.writeChildren();
+	}
+
+	private void createSubtree() {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+		ProgramNodeFactory nf = programModel.getProgramNodeFactory();
+		TreeNode root = programModel.getRootTreeNode(this);
+
+		try {
+			root.addChild(nf.createCommentNode().setComment("Add your nodes here"));
+			root.addChild(nf.createSetNode());
+			root.addChild(nf.createWaitNode());
+		} catch (TreeStructureException e) {
+			e.printStackTrace();
+			// See e.getMessage() for explanation
+		}
+	}
+
+}

+ 49 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeService.java

@@ -0,0 +1,49 @@
+package com.ur.urcap.examples.pickorplaceswing.open;
+
+import java.util.Locale;
+
+import com.ur.urcap.api.contribution.ViewAPIProvider;
+import com.ur.urcap.api.contribution.program.ContributionConfiguration;
+import com.ur.urcap.api.contribution.program.CreationContext;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeService;
+import com.ur.urcap.api.domain.SystemAPI;
+import com.ur.urcap.api.domain.data.DataModel;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.Style;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.V3Style;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.V5Style;
+
+public class GripperOpenProgramNodeService
+		implements SwingProgramNodeService<GripperOpenProgramNodeContribution, GripperOpenProgramNodeView> {
+
+	@Override
+	public String getTitle(Locale locale) {
+		return "Gripper Open";
+	}
+
+	@Override
+	public String getId() {
+		return "GripperOpenProgramNode";
+	}
+
+	@Override
+	public void configureContribution(ContributionConfiguration configuration) {
+		configuration.setDeprecated(false);
+		configuration.setUserInsertable(false);
+		configuration.setChildrenAllowed(true);
+	}
+
+	@Override
+	public GripperOpenProgramNodeView createView(ViewAPIProvider apiProvider) {
+		SystemAPI systemAPI = apiProvider.getSystemAPI();
+		Style style = systemAPI.getSoftwareVersion().getMajorVersion() >= 5 ? new V5Style() : new V3Style();
+		return new GripperOpenProgramNodeView(style);
+	}
+
+	@Override
+	public GripperOpenProgramNodeContribution createNode(ProgramAPIProvider apiProvider,
+			GripperOpenProgramNodeView view, DataModel model, CreationContext context) {
+		return new GripperOpenProgramNodeContribution(apiProvider);
+	}
+
+}

+ 24 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/open/GripperOpenProgramNodeView.java

@@ -0,0 +1,24 @@
+package com.ur.urcap.examples.pickorplaceswing.open;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+
+import com.ur.urcap.api.contribution.ContributionProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeView;
+import com.ur.urcap.examples.pickorplaceswing.pickorplace.Style;
+
+public class GripperOpenProgramNodeView implements SwingProgramNodeView<GripperOpenProgramNodeContribution> {
+
+	private final Style style;
+
+	GripperOpenProgramNodeView(Style style) {
+		this.style = style;
+	}
+
+	@Override
+	public void buildUI(JPanel panel, ContributionProvider<GripperOpenProgramNodeContribution> provider) {
+		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+		panel.add(style.createVerticalSpacing());
+		panel.add(style.createInfo("Opening of the gripper is specified in this subtree."));
+	}
+}

+ 163 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeContribution.java

@@ -0,0 +1,163 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+import com.ur.urcap.api.contribution.ProgramNodeContribution;
+import com.ur.urcap.api.contribution.program.CreationContext;
+import com.ur.urcap.api.contribution.program.CreationContext.NodeCreationType;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.domain.ProgramAPI;
+import com.ur.urcap.api.domain.data.DataModel;
+import com.ur.urcap.api.domain.program.ProgramModel;
+import com.ur.urcap.api.domain.program.nodes.ProgramNodeFactory;
+import com.ur.urcap.api.domain.program.structure.TreeNode;
+import com.ur.urcap.api.domain.program.structure.TreeStructureException;
+import com.ur.urcap.api.domain.script.ScriptWriter;
+import com.ur.urcap.api.domain.undoredo.UndoableChanges;
+import com.ur.urcap.examples.pickorplaceswing.close.GripperCloseProgramNodeService;
+import com.ur.urcap.examples.pickorplaceswing.open.GripperOpenProgramNodeService;
+
+public class PickOrPlaceProgramNodeContribution implements ProgramNodeContribution {
+
+	private static final String TEMPLATE_KEY = "templateType";
+
+	private final ProgramAPIProvider apiProvider;
+	private final PickOrPlaceProgramNodeView view;
+	private final DataModel model;
+
+	public PickOrPlaceProgramNodeContribution(ProgramAPIProvider apiProvider, PickOrPlaceProgramNodeView view,
+			DataModel model, CreationContext context) {
+		this.apiProvider = apiProvider;
+		this.view = view;
+		this.model = model;
+		lockChildSequence(apiProvider);
+		if (context.getNodeCreationType() == NodeCreationType.NEW) {
+			this.setModel(TemplateType.EMPTY.getName());
+		}
+	}
+
+	@Override
+	public String getTitle() {
+		return getTemplateType().getName();
+	}
+
+	@Override
+	public void openView() {
+		this.view.update(this);
+	}
+
+	@Override
+	public void closeView() {
+	}
+
+	@Override
+	public boolean isDefined() {
+		return true;
+	}
+
+	@Override
+	public void generateScript(ScriptWriter writer) {
+		writer.writeChildren();
+	}
+
+	private void setModel(final String variable) {
+		model.set(TEMPLATE_KEY, variable);
+	}
+
+	public void reset() {
+		apiProvider.getProgramAPI().getUndoRedoManager().recordChanges(new UndoableChanges() {
+			@Override
+			public void executeChanges() {
+				setModel(TemplateType.EMPTY.getName());
+				clearSubtree();
+				view.update(PickOrPlaceProgramNodeContribution.this);
+			}
+		});
+	}
+
+	public void createPick() {
+		apiProvider.getProgramAPI().getUndoRedoManager().recordChanges(new UndoableChanges() {
+			@Override
+			public void executeChanges() {
+				setModel(TemplateType.PICK.getName());
+				createSubtree(TemplateType.PICK);
+				view.update(PickOrPlaceProgramNodeContribution.this);
+			}
+		});
+	}
+
+	public void createPlace() {
+		apiProvider.getProgramAPI().getUndoRedoManager().recordChanges(new UndoableChanges() {
+			@Override
+			public void executeChanges() {
+				setModel(TemplateType.PLACE.getName());
+				createSubtree(TemplateType.PLACE);
+				view.update(PickOrPlaceProgramNodeContribution.this);
+			}
+		});
+	}
+
+	public TemplateType getTemplateType() {
+		String templateTypeName = model.get(TEMPLATE_KEY, TemplateType.EMPTY.getName());
+		return TemplateType.valueOfByName(templateTypeName);
+	}
+
+	private void clearSubtree() {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+
+		TreeNode tree = programModel.getRootTreeNode(this);
+		int size = childrenCount();
+		try {
+			for (int i = 0; i < size; i++) {
+				tree.removeChild(tree.getChildren().get(0));
+			}
+		} catch (TreeStructureException e) {
+			e.printStackTrace();
+			// See e.getMessage() for explanation
+		}
+	}
+
+	private int childrenCount() {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+		return programModel.getRootTreeNode(this).getChildren().size();
+	}
+
+	private void createSubtree(TemplateType template) {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+		ProgramNodeFactory nf = programModel.getProgramNodeFactory();
+		TreeNode root = programModel.getRootTreeNode(this);
+		try {
+			root.addChild(nf.createMoveNode());
+
+			addGripper(template, root, nf);
+
+			TreeNode folderRetract = root.addChild(nf.createFolderNode());
+			folderRetract.addChild(nf.createCommentNode().setComment("Please customize your functionality here"));
+		} catch (TreeStructureException e) {
+			e.printStackTrace();
+			// See e.getMessage() for explanation
+		}
+	}
+
+	private void addGripper(TemplateType template, TreeNode root, ProgramNodeFactory nf) throws TreeStructureException {
+		switch (template) {
+		case PICK:
+			root.addChild(nf.createURCapProgramNode(GripperCloseProgramNodeService.class));
+			break;
+		case PLACE:
+			root.addChild(nf.createURCapProgramNode(GripperOpenProgramNodeService.class));
+			break;
+		default:
+			break;
+		}
+	}
+
+	private void lockChildSequence(ProgramAPIProvider apiProvider) {
+		ProgramAPI programAPI = apiProvider.getProgramAPI();
+		ProgramModel programModel = programAPI.getProgramModel();
+		TreeNode root = programModel.getRootTreeNode(this);
+		root.setChildSequenceLocked(true);
+	}
+
+}

+ 46 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeService.java

@@ -0,0 +1,46 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+import java.util.Locale;
+
+import com.ur.urcap.api.contribution.ViewAPIProvider;
+import com.ur.urcap.api.contribution.program.ContributionConfiguration;
+import com.ur.urcap.api.contribution.program.CreationContext;
+import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeService;
+import com.ur.urcap.api.domain.SystemAPI;
+import com.ur.urcap.api.domain.data.DataModel;
+
+public class PickOrPlaceProgramNodeService
+		implements SwingProgramNodeService<PickOrPlaceProgramNodeContribution, PickOrPlaceProgramNodeView> {
+
+	@Override
+	public String getId() {
+		return "PickOrPlaceProgramNode";
+	}
+
+	@Override
+	public String getTitle(Locale locale) {
+		return "Pick or Place Swing";
+	}
+
+	@Override
+	public void configureContribution(ContributionConfiguration configuration) {
+		configuration.setDeprecated(false);
+		configuration.setChildrenAllowed(true);
+		configuration.setUserInsertable(true);
+	}
+
+	@Override
+	public PickOrPlaceProgramNodeView createView(ViewAPIProvider apiProvider) {
+		SystemAPI systemAPI = apiProvider.getSystemAPI();
+		Style style = systemAPI.getSoftwareVersion().getMajorVersion() >= 5 ? new V5Style() : new V3Style();
+		return new PickOrPlaceProgramNodeView(style);
+	}
+
+	@Override
+	public PickOrPlaceProgramNodeContribution createNode(ProgramAPIProvider apiProvider,
+			PickOrPlaceProgramNodeView view, DataModel model, CreationContext context) {
+		return new PickOrPlaceProgramNodeContribution(apiProvider, view, model, context);
+	}
+
+}

+ 109 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/PickOrPlaceProgramNodeView.java

@@ -0,0 +1,109 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import com.ur.urcap.api.contribution.ContributionProvider;
+import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeView;
+
+public class PickOrPlaceProgramNodeView implements SwingProgramNodeView<PickOrPlaceProgramNodeContribution> {
+
+	private final Style style;
+
+	private JButton placeButton;
+	private JButton pickButton;
+	private JButton resetButton;
+
+	public PickOrPlaceProgramNodeView(Style style) {
+		this.style = style;
+	}
+
+	@Override
+	public void buildUI(final JPanel panel, final ContributionProvider<PickOrPlaceProgramNodeContribution> provider) {
+		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+		panel.add(createMakeSection(provider));
+		panel.add(createResetSection(provider));
+	}
+
+	private Component createMakeSection(final ContributionProvider<PickOrPlaceProgramNodeContribution> provider) {
+		Box section = style.createSection(BoxLayout.PAGE_AXIS);
+
+		Box infoSection = style.createSection(BoxLayout.PAGE_AXIS);
+		infoSection.add(style.createInfo("Choose Pick or Place:"));
+		infoSection.add(style.createVerticalSpacing());
+		section.add(infoSection);
+
+		Box buttonSection = style.createSection(BoxLayout.LINE_AXIS);
+		buttonSection.add(style.createHorizontalIndent());
+		this.pickButton = style.createButton("Pick");
+		this.pickButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				provider.get().createPick();
+			}
+		});
+		buttonSection.add(pickButton, FlowLayout.LEFT);
+
+		buttonSection.add(style.createHorizontalSpacing());
+		this.placeButton = style.createButton("Place");
+		this.placeButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				provider.get().createPlace();
+			}
+		});
+		buttonSection.add(placeButton);
+
+		section.add(buttonSection);
+		return section;
+	}
+
+	private Component createResetSection(final ContributionProvider<PickOrPlaceProgramNodeContribution> provider) {
+		Box section = style.createSection(BoxLayout.PAGE_AXIS);
+
+		section.add(style.createVerticalSpacing());
+
+		Box infoSection = style.createSection(BoxLayout.PAGE_AXIS);
+		infoSection.add(style.createVerticalSpacing());
+		infoSection.add(style.createInfo("Tap the button to reset your selection."));
+		infoSection.add(style.createVerticalSpacing());
+		infoSection.add(style.createInfo("This removes the program tree and clears all configuration data."));
+		infoSection.add(style.createVerticalSpacing());
+		section.add(infoSection);
+
+		Box buttonSection = style.createSection(BoxLayout.LINE_AXIS);
+		buttonSection.add(style.createHorizontalIndent());
+		this.resetButton = style.createButton("Reset");
+		this.resetButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				provider.get().reset();
+			}
+		});
+		buttonSection.add(this.resetButton, FlowLayout.LEFT);
+		section.add(buttonSection);
+
+		return section;
+	}
+
+	void update(PickOrPlaceProgramNodeContribution contribution) {
+		TemplateType templateType = contribution.getTemplateType();
+
+		if (templateType == TemplateType.EMPTY) {
+			pickButton.setEnabled(true);
+			placeButton.setEnabled(true);
+			resetButton.setEnabled(false);
+		} else {
+			pickButton.setEnabled(false);
+			placeButton.setEnabled(false);
+			resetButton.setEnabled(true);
+		}
+	}
+
+}

+ 44 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/Style.java

@@ -0,0 +1,44 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+import javax.swing.*;
+import java.awt.*;
+
+public abstract class Style {
+
+	protected abstract int getHorizontalSpacing();
+
+	protected abstract int getVerticalSpacing();
+
+	protected abstract int getHorizontalIndent();
+
+	public Box createInfo(String text) {
+		Box infoBox = Box.createHorizontalBox();
+		infoBox.setAlignmentX(Component.LEFT_ALIGNMENT);
+		infoBox.add(new JLabel(text));
+		return infoBox;
+	}
+
+	public Component createHorizontalSpacing() {
+		return Box.createRigidArea(new Dimension(getHorizontalSpacing(), 0));
+	}
+
+	public Component createHorizontalIndent() {
+		return Box.createRigidArea(new Dimension(getHorizontalIndent(), 0));
+	}
+
+	public Component createVerticalSpacing() {
+		return Box.createRigidArea(new Dimension(0, getVerticalSpacing()));
+	}
+
+	public JButton createButton(String text) {
+		return new JButton(text);
+	}
+
+	public Box createSection(int axis) {
+		Box panel = new Box(axis);
+		panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+		panel.setAlignmentY(Component.TOP_ALIGNMENT);
+		return panel;
+	}
+
+}

+ 25 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/TemplateType.java

@@ -0,0 +1,25 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+public enum TemplateType {
+
+	EMPTY("Pick or Place Swing"), PICK("Pick"), PLACE("Place");
+
+	private final String name;
+
+	TemplateType(final String name) {
+		this.name = name;
+	}
+
+	public final String getName() {
+		return name;
+	}
+
+	public static TemplateType valueOfByName(String name) {
+		if (PICK.name.equals(name)) {
+			return PICK;
+		} else if (PLACE.name.equals(name)) {
+			return PLACE;
+		}
+		return EMPTY;
+	}
+}

+ 24 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/V3Style.java

@@ -0,0 +1,24 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+public class V3Style extends Style {
+
+	private static final int HORIZONTAL_SPACING = 5;
+	private static final int VERTICAL_SPACING = 15;
+	private static final int HORIZONTAL_INDENT = 20;
+
+	@Override
+	protected int getHorizontalSpacing() {
+		return HORIZONTAL_SPACING;
+	}
+
+	@Override
+	protected int getVerticalSpacing() {
+		return VERTICAL_SPACING;
+	}
+
+	@Override
+	protected int getHorizontalIndent() {
+		return HORIZONTAL_INDENT;
+	}
+
+}

+ 24 - 0
src/main/java/com/ur/urcap/examples/pickorplaceswing/pickorplace/V5Style.java

@@ -0,0 +1,24 @@
+package com.ur.urcap.examples.pickorplaceswing.pickorplace;
+
+public class V5Style extends Style {
+
+	private static final int HORIZONTAL_SPACING = 10;
+	private static final int VERTICAL_SPACING = 15;
+	private static final int HORIZONTAL_INDENT = 20;
+
+	@Override
+	protected int getHorizontalSpacing() {
+		return HORIZONTAL_SPACING;
+	}
+
+	@Override
+	protected int getVerticalSpacing() {
+		return VERTICAL_SPACING;
+	}
+
+	@Override
+	protected int getHorizontalIndent() {
+		return HORIZONTAL_INDENT;
+	}
+
+}

+ 28 - 0
src/main/resources/META-INF/LICENSE

@@ -0,0 +1,28 @@
+Example:
+Copyright (c) <year>, <copyright holder>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+   This product includes software developed by the <organization>.
+4. Neither the name of the <organization> nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.