Skip to content

Commit 6435def

Browse files
authored
Add code generation UI and hooks for WPILib VisionPipeline (#741)
1 parent e75b1f6 commit 6435def

File tree

81 files changed

+956
-235
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+956
-235
lines changed

core/src/main/java/edu/wpi/grip/core/Pipeline.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package edu.wpi.grip.core;
22

33
import edu.wpi.grip.core.events.AppSettingsChangedEvent;
4+
import edu.wpi.grip.core.events.CodeGenerationSettingsChangedEvent;
45
import edu.wpi.grip.core.events.ConnectionAddedEvent;
56
import edu.wpi.grip.core.events.ConnectionRemovedEvent;
67
import edu.wpi.grip.core.events.ProjectSettingsChangedEvent;
@@ -10,6 +11,7 @@
1011
import edu.wpi.grip.core.events.StepMovedEvent;
1112
import edu.wpi.grip.core.events.StepRemovedEvent;
1213
import edu.wpi.grip.core.settings.AppSettings;
14+
import edu.wpi.grip.core.settings.CodeGenerationSettings;
1315
import edu.wpi.grip.core.settings.ProjectSettings;
1416
import edu.wpi.grip.core.settings.SettingsProvider;
1517
import edu.wpi.grip.core.sockets.InputSocket;
@@ -68,6 +70,7 @@ public class Pipeline implements ConnectionValidator, SettingsProvider, StepInde
6870
private ProjectSettings settings = new ProjectSettings();
6971
@XStreamOmitField
7072
private transient AppSettings appSettings = new AppSettings(); // Do not serialize this field
73+
private CodeGenerationSettings codeGenerationSettings = CodeGenerationSettings.DEFAULT_SETTINGS;
7174

7275
/**
7376
* Locks the resource with the specified lock and performs the function. When the function is
@@ -197,6 +200,11 @@ public AppSettings getAppSettings() {
197200
return appSettings;
198201
}
199202

203+
@Override
204+
public CodeGenerationSettings getCodeGenerationSettings() {
205+
return codeGenerationSettings;
206+
}
207+
200208
@SuppressWarnings("unchecked")
201209
@Override
202210
public boolean canConnect(OutputSocket<?> outputSocket, InputSocket<?> inputSocket) {
@@ -406,4 +414,9 @@ public void onAppSettingsChanged(AppSettingsChangedEvent event) {
406414
this.appSettings = event.getAppSettings();
407415
}
408416

417+
@Subscribe
418+
public void onCodeGenerationSettingsChanged(CodeGenerationSettingsChangedEvent event) {
419+
this.codeGenerationSettings = event.getCodeGenerationSettings();
420+
}
421+
409422
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package edu.wpi.grip.core.events;
2+
3+
import edu.wpi.grip.core.settings.CodeGenerationSettings;
4+
5+
import static com.google.common.base.Preconditions.checkNotNull;
6+
7+
/**
8+
* An event fired when code generation settings are changed.
9+
*/
10+
public class CodeGenerationSettingsChangedEvent implements DirtiesSaveEvent {
11+
12+
private final CodeGenerationSettings settings;
13+
14+
public CodeGenerationSettingsChangedEvent(CodeGenerationSettings settings) {
15+
this.settings = checkNotNull(settings, "settings");
16+
}
17+
18+
public CodeGenerationSettings getCodeGenerationSettings() {
19+
return settings;
20+
}
21+
22+
}

core/src/main/java/edu/wpi/grip/core/events/ConnectionRemovedEvent.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
* user deleting a connection with the GUI.
1212
*/
1313
public class ConnectionRemovedEvent implements DirtiesSaveEvent {
14-
private final Connection connection;
14+
private final Connection<?> connection;
1515

1616
/**
1717
* @param connection The connection being deleted.
1818
*/
19-
public ConnectionRemovedEvent(Connection connection) {
19+
public ConnectionRemovedEvent(Connection<?> connection) {
2020
this.connection = checkNotNull(connection, "Connection cannot be null");
2121
}
2222

2323
/**
2424
* @return The connection being deleted.
2525
*/
26-
public Connection getConnection() {
26+
public Connection<?> getConnection() {
2727
return this.connection;
2828
}
2929

core/src/main/java/edu/wpi/grip/core/events/ProjectSettingsChangedEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* This event is posted after the {@link ProjectSettings} are changed so anything that relies on
99
* them can immediately update without restarting the application.
1010
*/
11-
public class ProjectSettingsChangedEvent {
11+
public class ProjectSettingsChangedEvent implements DirtiesSaveEvent {
1212
private final ProjectSettings projectSettings;
1313

1414
public ProjectSettingsChangedEvent(ProjectSettings projectSettings) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package edu.wpi.grip.core.serialization;
2+
3+
import edu.wpi.grip.core.events.CodeGenerationSettingsChangedEvent;
4+
import edu.wpi.grip.core.settings.CodeGenerationSettings;
5+
6+
import com.google.common.eventbus.EventBus;
7+
import com.google.inject.Inject;
8+
import com.thoughtworks.xstream.converters.UnmarshallingContext;
9+
import com.thoughtworks.xstream.converters.reflection.ReflectionConverter;
10+
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
11+
12+
/**
13+
* XStream converter for {@link edu.wpi.grip.core.settings.CodeGenerationSettings}.
14+
*/
15+
public class CodeGenerationSettingsConverter extends ReflectionConverter {
16+
17+
private final EventBus eventBus;
18+
19+
@Inject
20+
public CodeGenerationSettingsConverter(Project project, EventBus eventBus) {
21+
super(project.xstream.getMapper(),
22+
project.xstream.getReflectionProvider(),
23+
CodeGenerationSettings.class);
24+
this.eventBus = eventBus;
25+
}
26+
27+
@Override
28+
public CodeGenerationSettings unmarshal(HierarchicalStreamReader reader,
29+
UnmarshallingContext context) {
30+
CodeGenerationSettings settings = (CodeGenerationSettings) super.unmarshal(reader, context);
31+
eventBus.post(new CodeGenerationSettingsChangedEvent(settings));
32+
return settings;
33+
}
34+
35+
}

core/src/main/java/edu/wpi/grip/core/serialization/Project.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@ public void initialize(StepConverter stepConverter,
4747
SourceConverter sourceConverter,
4848
SocketConverter socketConverter,
4949
ConnectionConverter connectionConverter,
50-
ProjectSettingsConverter projectSettingsConverter) {
50+
ProjectSettingsConverter projectSettingsConverter,
51+
CodeGenerationSettingsConverter codeGenerationSettingsConverter) {
5152
xstream.setMode(XStream.NO_REFERENCES);
5253
xstream.ignoreUnknownElements(); // ignores all unknown tags
5354
xstream.registerConverter(stepConverter);
5455
xstream.registerConverter(sourceConverter);
5556
xstream.registerConverter(socketConverter);
5657
xstream.registerConverter(connectionConverter);
5758
xstream.registerConverter(projectSettingsConverter);
59+
xstream.registerConverter(codeGenerationSettingsConverter);
5860
try {
5961
ClassPath cp = ClassPath.from(getClass().getClassLoader());
6062
cp.getAllClasses()
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
package edu.wpi.grip.core.settings;
2+
3+
import static com.google.common.base.Preconditions.checkArgument;
4+
import static com.google.common.base.Preconditions.checkNotNull;
5+
6+
/**
7+
* Holds options for code generation.
8+
*/
9+
public class CodeGenerationSettings {
10+
11+
private final String language;
12+
private final String className;
13+
private final boolean implementWpilibPipeline;
14+
private final String saveDir;
15+
private final String packageName;
16+
private final String moduleName;
17+
18+
public static final String LANGUAGE = "language";
19+
public static final String CLASS_NAME = "className";
20+
public static final String IMPLEMENT_WPILIB_PIPELINE = "implementVisionPipeline";
21+
public static final String SAVE_DIR = "saveDir";
22+
public static final String PACKAGE_NAME = "packageName";
23+
public static final String MODULE_NAME = "moduleName";
24+
25+
26+
/**
27+
* The default code generation settings.
28+
* <br>
29+
* <table>
30+
* <tr><td>Language</td><td>Java</td></tr>
31+
* <tr><td>Class name</td><td>GripPipeline</td></tr>
32+
* <tr><td>Implement WPILib API</td><td>false</td></tr>
33+
* <tr><td>Save directory</td><td>User home</td></tr>
34+
* <tr><td>Java package</td><td>Default package</td></tr>
35+
* <tr><td>Python module</td><td>grip</td></tr>
36+
* </table>
37+
*/
38+
public static final CodeGenerationSettings DEFAULT_SETTINGS = new CodeGenerationSettings();
39+
40+
/**
41+
* Creates the default code generation settings.
42+
* <br>
43+
* <table>
44+
* <tr><td>Language</td><td>Java</td></tr>
45+
* <tr><td>Class name</td><td>GripPipeline</td></tr>
46+
* <tr><td>Implement WPILib API</td><td>false</td></tr>
47+
* <tr><td>Save directory</td><td>User home</td></tr>
48+
* <tr><td>Java package</td><td>Default package</td></tr>
49+
* <tr><td>Python module</td><td>grip</td></tr>
50+
* </table>
51+
*/
52+
CodeGenerationSettings() {
53+
this("Java", "GripPipeline", false, System.getProperty("user.home"), "", "grip");
54+
}
55+
56+
/**
57+
* Private constructor; use a builder.
58+
*
59+
* @param language the language to generate to
60+
* @param className the name of the class to generate
61+
* @param implementWpilibPipeline if the generated class should implement the
62+
* WPILib VisionPipeline interface
63+
* @param saveDir the directory to save the generated file to
64+
* @param packageName the name of the Java package to place the file in
65+
* @param moduleName the name of the Python module
66+
*/
67+
private CodeGenerationSettings(String language,
68+
String className,
69+
boolean implementWpilibPipeline,
70+
String saveDir,
71+
String packageName,
72+
String moduleName) {
73+
this.language = language;
74+
this.className = className;
75+
this.implementWpilibPipeline = implementWpilibPipeline;
76+
this.saveDir = saveDir;
77+
this.packageName = packageName;
78+
this.moduleName = moduleName;
79+
}
80+
81+
public String getLanguage() {
82+
return language;
83+
}
84+
85+
public String getClassName() {
86+
return className;
87+
}
88+
89+
public boolean shouldImplementWpilibPipeline() {
90+
return implementWpilibPipeline;
91+
}
92+
93+
public String getSaveDir() {
94+
return saveDir;
95+
}
96+
97+
public String getPackageName() {
98+
return packageName;
99+
}
100+
101+
public String getModuleName() {
102+
return moduleName;
103+
}
104+
105+
public static Builder builder() {
106+
return new Builder();
107+
}
108+
109+
public static final class Builder {
110+
111+
private String language;
112+
private String className;
113+
private Boolean implementVisionPipeline;
114+
private String saveDir;
115+
private String packageName;
116+
private String moduleName;
117+
118+
private Builder() {
119+
}
120+
121+
/**
122+
* Sets the language. Must be one of "Java", "C++", "Python.
123+
*/
124+
public Builder language(String language) {
125+
checkArgument(language.matches("Java|C\\+\\+|Python"));
126+
this.language = language;
127+
return this;
128+
}
129+
130+
/**
131+
* Sets the generated class name.
132+
*/
133+
public Builder className(String className) {
134+
this.className = checkNotNull(className);
135+
return this;
136+
}
137+
138+
/**
139+
* Sets the directory code should be generated in.
140+
*/
141+
public Builder saveDir(String saveDir) {
142+
this.saveDir = checkNotNull(saveDir);
143+
return this;
144+
}
145+
146+
/**
147+
* Sets if the generated pipeline should implement the WPILib API.
148+
*/
149+
public Builder implementVisionPipeline(boolean implementVisionPipeline) {
150+
this.implementVisionPipeline = implementVisionPipeline;
151+
return this;
152+
}
153+
154+
/**
155+
* Sets the package of the generated Java class.
156+
*/
157+
public Builder packageName(String packageName) {
158+
this.packageName = checkNotNull(packageName);
159+
return this;
160+
}
161+
162+
/**
163+
* Sets the module name (also file name) of the generated Python class.
164+
*/
165+
public Builder moduleName(String moduleName) {
166+
this.moduleName = checkNotNull(moduleName);
167+
return this;
168+
}
169+
170+
/**
171+
* Builds a new {@code CodeGenerationSettings} object. This ensures that every required
172+
* option has been set.
173+
*/
174+
public CodeGenerationSettings build() {
175+
return new CodeGenerationSettings(
176+
checkNotNull(language, LANGUAGE),
177+
checkNotNull(className, CLASS_NAME),
178+
checkNotNull(implementVisionPipeline, IMPLEMENT_WPILIB_PIPELINE),
179+
checkNotNull(saveDir, SAVE_DIR),
180+
checkNotNull(packageName, PACKAGE_NAME),
181+
checkNotNull(moduleName, MODULE_NAME)
182+
);
183+
}
184+
185+
}
186+
187+
}

core/src/main/java/edu/wpi/grip/core/settings/ProjectSettings.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public class ProjectSettings implements Settings, Cloneable {
4343
private String deployJvmOptions = "-Xmx50m -XX:-OmitStackTraceInFastThrow "
4444
+ "-XX:+HeapDumpOnOutOfMemoryError -XX:MaxNewSize=16m";
4545

46+
47+
// Getters and setters
48+
49+
4650
public int getTeamNumber() {
4751
return teamNumber;
4852
}

core/src/main/java/edu/wpi/grip/core/settings/SettingsProvider.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@ public interface SettingsProvider {
2424
*/
2525
AppSettings getAppSettings();
2626

27+
/**
28+
* Gets the current code generation settings. This object may become out of date if the settings
29+
* are edited by the user, so objects requiring a preference value should also subscribe to
30+
* {@link edu.wpi.grip.core.events.AppSettingsChangedEvent} to get updates.
31+
*
32+
* @return the current code generation settings
33+
*/
34+
CodeGenerationSettings getCodeGenerationSettings();
35+
2736
}

0 commit comments

Comments
 (0)