Initial checkin of unified hierarchy of WPILib 2015

This commit is contained in:
Brad Miller
2013-12-15 18:30:16 -05:00
commit 3178911eef
1560 changed files with 410007 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?><!-- You may freely edit this file. See commented blocks below for --><!-- some examples of how to customize the build. --><!-- (If you delete it and reopen the project it will be recreated.) --><!-- By default, only the Clean and Build commands use this build script. --><project name="JavaNetworkTableViewer" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
<description>Builds, tests, and runs the project JavaNetworkTableViewer.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. Those of them relevant for JavaFX project are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-jfx-jar: called before FX SDK specific <fx:jar> task
-post-jfx-jar: called after FX SDK specific <fx:jar> task
-pre-jfx-deploy: called before FX SDK specific <fx:deploy> task
-post-jfx-deploy: called after FX SDK specific <fx:deploy> task
-pre-jfx-native: called just after -pre-jfx-deploy if <fx:deploy> runs in native packaging mode
-post-jfx-native: called just after -post-jfx-deploy if <fx:deploy> runs in native packaging mode
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting a HTML postprocessor after javaFX SDK deployment:
<target name="-post-jfx-deploy">
<basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
<property name="jfx.deployment.html" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}.html"/>
<custompostprocess>
<fileset dir="${jfx.deployment.html}"/>
</custompostprocess>
</target>
Example of calling an Ant task from JavaFX SDK. Note that access to JavaFX SDK Ant tasks must be
initialized; to ensure this is done add the dependence on -check-jfx-sdk-version target:
<target name="-post-jfx-jar" depends="-check-jfx-sdk-version">
<echo message="Calling jar task from JavaFX SDK"/>
<fx:jar ...>
...
</fx:jar>
</target>
For more details about JavaFX SDK Ant tasks go to
http://docs.oracle.com/javafx/2/deployment/jfxpub-deployment.htm
For list of available properties check the files
nbproject/build-impl.xml and nbproject/jfx-impl.xml.
-->
</project>

View File

@@ -0,0 +1,18 @@
libs.CopyLibs.classpath=\
${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar
libs.CopyLibs.displayName=CopyLibs Task
libs.CopyLibs.prop-version=1.0
libs.junit.classpath=\
${base}/junit/junit-3.8.2.jar
libs.junit.displayName=JUnit 3.8.2
libs.junit.javadoc=\
${base}/junit/junit-3.8.2-api.zip
libs.junit.prop-maven-dependencies=junit:junit:3.8.2:jar
libs.junit_4.classpath=\
${base}/junit_4/junit-4.10.jar
libs.junit_4.displayName=JUnit 4.10
libs.junit_4.javadoc=\
${base}/junit_4/junit-4.10-javadoc.jar
libs.junit_4.prop-maven-dependencies=junit:junit:4.10:jar
libs.junit_4.src=\
${base}/junit_4/junit-4.10-sources.jar

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
# Do not modify this property in this configuration. It can be re-generated.
$label=Run as WebStart

View File

@@ -0,0 +1,2 @@
# Do not modify this property in this configuration. It can be re-generated.
$label=Run in Browser

View File

@@ -0,0 +1,8 @@
build.xml.data.CRC32=c8c66866
build.xml.script.CRC32=d06c8c20
build.xml.stylesheet.CRC32=28e38971@1.56.1.46
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=9e01e615
nbproject/build-impl.xml.script.CRC32=31676db4
nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
# Do not modify this property in this configuration. It can be re-generated.
$label=Run as WebStart
# Do not modify this property in this configuration. It can be re-generated.
javafx.run.as=webstart

View File

@@ -0,0 +1,4 @@
# Do not modify this property in this configuration. It can be re-generated.
$label=Run in Browser
# Do not modify this property in this configuration. It can be re-generated.
javafx.run.as=embedded

View File

@@ -0,0 +1,12 @@
auxiliary.org-netbeans-modules-projectapi.issue214819_5f_fx_5f_enabled=true
compile.on.save=true
do.depend=false
do.jar=true
# No need to modify this property unless customizing JavaFX Ant task infrastructure
endorsed.javafx.ant.classpath=.
javac.debug=true
javadoc.preview=true
javafx.run.as=standalone
javafx.run.inbrowser=<Default System Browser>
javafx.run.inbrowser.path=C:\\Users\\Sam\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe
user.properties.file=C:\\Users\\Sam\\AppData\\Roaming\\NetBeans\\7.3\\build.properties

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
</project-private>

View File

@@ -0,0 +1,120 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=NetworkTableViewer
application.vendor=
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
compile.on.save=true
compile.on.save.unsupported.javafx=true
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/NetworkTableViewer.jar
dist.javadoc.dir=${dist.dir}/javadoc
endorsed.classpath=
excludes=
file.reference.networktables-desktop.jar=lib\\networktables-desktop.jar
includes=**
# Non-JavaFX jar file creation is deactivated in JavaFX 2.0+ projects
jar.archive.disabled=true
jar.compress=false
javac.classpath=\
${javafx.runtime}/lib/jfxrt.jar:\
${javafx.runtime}/lib/deploy.jar:\
${javafx.runtime}/lib/javaws.jar:\
${javafx.runtime}/lib/plugin.jar:\
${file.reference.networktables-desktop.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.processorpath=\
${javac.classpath}
javac.source=1.7
javac.target=1.7
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit_4.classpath}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=true
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
javafx.binarycss=false
javafx.deploy.adddesktopshortcut=false
javafx.deploy.addstartmenushortcut=false
javafx.deploy.allowoffline=true
# If true, application update mode is set to 'background', if false, update mode is set to 'eager'
javafx.deploy.backgroundupdate=false
javafx.deploy.embedJNLP=true
javafx.deploy.includeDT=true
javafx.deploy.installpermanently=false
javafx.deploy.permissionselevated=true
# Set true to prevent creation of temporary copy of deployment artifacts before each run (disables concurrent runs)
javafx.disable.concurrent.runs=false
# Set true to enable multiple concurrent runs of the same WebStart or Run-in-Browser project
javafx.enable.concurrent.external.runs=false
# This is a JavaFX project
javafx.enabled=true
javafx.fallback.class=com.javafx.main.NoJavaFXFallback
# Main class for JavaFX
javafx.main.class=edu.wpi.first.tableviewer.NetworkTableViewer
javafx.native.bundling.enabled=false
javafx.native.bundling.type=all
javafx.preloader.class=
# This project does not use Preloader
javafx.preloader.enabled=false
javafx.preloader.jar.filename=
javafx.preloader.jar.path=
javafx.preloader.project.path=
javafx.preloader.type=none
# Set true for GlassFish only. Rebases manifest classpaths of JARs in lib dir. Not usable with signed JARs.
javafx.rebase.libs=false
javafx.run.height=600
javafx.run.width=800
javafx.runtime=${platforms.JDK_1.7.0_21.javafx.runtime.home}
javafx.sdk=${platforms.JDK_1.7.0_21.javafx.sdk.home}
javafx.signing.enabled=true
javafx.signing.type=self
# Pre-JavaFX 2.0 WebStart is deactivated in JavaFX 2.0+ projects
jnlp.enabled=false
# Main class for Java launcher
main.class=com.javafx.main.Main
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=JDK_1.7.0_21
run.classpath=\
${dist.jar}:\
${javac.classpath}
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
source.reference.networktables-desktop.jar=../java/dist/desktop-lib/networktables-desktop.src.zip
src.dir=src
test.src.dir=test

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">
<extension file="jfx-impl.xml" id="jfx">
<dependency dependsOn="-check-javafx" target="-init-check"/>
<dependency dependsOn="-jfx-copylibs" target="-post-jar"/>
<dependency dependsOn="-rebase-libs" target="-post-jar"/>
<dependency dependsOn="jfx-deployment" target="-post-jar"/>
<dependency dependsOn="jar" target="debug"/>
<dependency dependsOn="-jfx-copylibs" target="jar"/>
<dependency dependsOn="-rebase-libs" target="jar"/>
<dependency dependsOn="jar" target="profile"/>
<dependency dependsOn="jar" target="run"/>
</extension>
</buildExtensions>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>NetworkTableViewer</name>
<explicit-platform explicit-source-supported="true"/>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
<libraries xmlns="http://www.netbeans.org/ns/ant-project-libraries/1">
<definitions>.\lib\nblibraries.properties</definitions>
</libraries>
<spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
<word>popup</word>
</spellchecker-wordlist>
</configuration>
</project>

Binary file not shown.

View File

@@ -0,0 +1,27 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer;
import edu.wpi.first.tableviewer.popup.PreferencesPopup;
import edu.wpi.first.tableviewer.treeview.TableTreeView;
import javafx.application.Application;
import javafx.stage.Stage;
/**
*
* @author Sam
*/
public class NetworkTableViewer extends Application {
@Override
public void start(Stage stage) {
PreferencesPopup preferencesPopup = new PreferencesPopup();
preferencesPopup.showPopup();
TableTreeView view = new TableTreeView(preferencesPopup.getNode());
view.show();
}
}

View File

@@ -0,0 +1,159 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
import edu.wpi.first.wpilibj.tables.ITable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
/**
*
* @author Sam
*/
class AddValuePopup extends Popup {
public enum InputType {
BOOLEAN, NUMBER, STRING, SUBTABLE
}
private final InputType type;
private final ITable table;
public AddValuePopup(ITable table, InputType type) {
super();
this.table = table;
this.type = type;
initModality(Modality.WINDOW_MODAL);
}
@Override
public void showPopup() {
initComponents();
showAndWait();
}
@Override
public void initComponents() {
initComponents(type);
}
private void initComponents(final InputType type) {
final Scene scene = new Scene(new Group());
scene.setFill(Color.WHITESMOKE);
scene.getStylesheets().add(
"edu/wpi/first/tableviewer/stylesheets/ViewerStyleSheet.css");
final Label messageLabel = new Label();
final Label keyLabel = new Label("Key:");
final Label valueLabel = new Label("Value:");
final TextField keyField = new TextField();
final Button confirm = new Button("Add");
keyField.setPromptText("Key");
keyField.setPrefWidth(100);
final Control valueControl;
ObservableList<String> booleanOptions = FXCollections.observableArrayList("True", "False");
switch (type) {
case BOOLEAN:
messageLabel.setText("Add boolean");
valueControl = new ComboBox(booleanOptions);
((ComboBox) valueControl).getSelectionModel().select(0);
confirm.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
if (table.containsKey(keyField.getText())) {
PopupFactory.showErrorDialog("Key already in use!");
} else {
table.putBoolean(keyField.getText(), ((ComboBox) valueControl).getSelectionModel().isSelected(0));
close();
}
}
});
break;
case NUMBER:
messageLabel.setText("Add number");
valueControl = new TextField();
((TextField) valueControl).setPromptText("Number");
confirm.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
try {
if (table.containsKey(keyField.getText())) {
PopupFactory.showErrorDialog("Key already in use!");
} else {
table.putNumber(keyField.getText(), Double.parseDouble(((TextField) valueControl).getText()));
close();
}
} catch (NumberFormatException ex) {
PopupFactory.showErrorDialog("Invalid number!");
}
}
});
break;
case STRING:
messageLabel.setText("Add string");
valueControl = new TextField();
((TextField) valueControl).setPromptText("Text");
confirm.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
if (table.containsKey(keyField.getText())) {
PopupFactory.showErrorDialog("Key already in use!");
} else {
table.putString(keyField.getText(), ((TextField) valueControl).getText());
close();
}
}
});
break;
case SUBTABLE:
keyLabel.setText("Table name");
keyField.setPromptText("Name");
valueControl = null;
confirm.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
//TODO make a subtable show up without putting a value
ITable i = table.getSubTable(keyField.getText());
close();
}
});
break;
default:
return;
}
final GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(5);
grid.add(keyLabel, 1, 1);
grid.add(keyField, 2, 1);
if (type != InputType.SUBTABLE) {
grid.add(valueLabel, 1, 2);
grid.add(valueControl, 2, 2);
valueControl.setPrefWidth(100);
}
grid.add(confirm, 2, 3);
((Group) scene.getRoot()).getChildren().add(grid);
setScene(scene);
}
}

View File

@@ -0,0 +1,128 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
import edu.wpi.first.tableviewer.treeview.TableLeaf;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
/**
*
* @author Sam
*/
public class EditorPopup extends Popup {
private final Label inputLabel = new Label();
private final TextField inputField = new TextField();
private final ComboBox booleanBox = new ComboBox(FXCollections.observableArrayList("True", "False"));
private final Button okayButton = new Button("OK"),
cancelButton = new Button("Cancel");
private final String itemType;
private final TableLeaf leaf;
public EditorPopup(TableLeaf leaf) {
super("Edit Value", null, null);
this.leaf = leaf;
String tableValue = leaf.getTableValue().toString();
String tableKey = leaf.getTableKey();
inputLabel.setText(tableKey+":");
inputField.setText(tableValue);
inputField.setPromptText("New value");
inputField.setPrefWidth(100);
booleanBox.getSelectionModel().selectFirst();
itemType = leaf.getType().toString();
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
close();
}
});
}
@Override
public void initComponents() {
initComponents(itemType);
}
private void initComponents(final String type) {
final Scene scene = new Scene(new Group());
scene.setFill(Color.WHITESMOKE);
scene.getStylesheets().add(
"edu/wpi/first/tableviewer/stylesheets/ViewerStyleSheet.css");
final GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(15);
grid.setPadding(new Insets(5, 5, 5, 5));
grid.setAlignment(Pos.CENTER);
grid.add(inputLabel, 0, 1);
((Group) scene.getRoot()).getChildren().add(grid);
setScene(scene);
switch (type.toLowerCase()) {
case "boolean":
grid.add(booleanBox, 1, 1);
okayButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
leaf.updateValue(booleanBox.getSelectionModel().isSelected(0));
leaf.setExpanded(false); // refresh the leaf to updateValue the shown value
leaf.setExpanded(true);
close();
}
});
break;
case "number":
grid.add(inputField, 1, 1);
okayButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
try {
leaf.updateValue(Double.parseDouble(inputField.getText()));
leaf.setExpanded(false); // refresh the leaf to updateValue the shown value
leaf.setExpanded(true);
close();
} catch (NumberFormatException ex) {
PopupFactory.showErrorDialog("Invalid number value!");
}
}
});
break;
case "string":
grid.add(inputField, 1, 1);
okayButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
leaf.updateValue(inputField.getText());
leaf.setExpanded(false); // refresh the leaf to updateValue the shown value
leaf.setExpanded(true);
close();
}
});
break;
}
grid.add(okayButton, 0, 2);
grid.add(cancelButton, 1, 2);
}
}

View File

@@ -0,0 +1,35 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
/**
* An interface for defining popups.
* @author Sam
* @see Popup
* @see InputPopup
*/
public interface IPopup {
/**
* An enumeration representing the type of popup this is.
*/
public enum Type {
MESSAGE,
WARNING,
ERROR,
INPUT
}
/**
* A method used to show this popup.
*/
public void showPopup();
/**
* Initialize all components in this popup.
*/
public void initComponents();
}

View File

@@ -0,0 +1,115 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.stage.Modality;
import javafx.stage.Stage;
/**
* A generic popup. Call
* {@link PopupFactory Popupfactory}.{@code showXXXXDialog()} to show a
* predefined popup of a specific type.
*
* @see IPopup
* @see InputPopup
* @see PopupFactory
* @author Sam
*/
class Popup extends Stage implements IPopup {
protected final String message;
protected final Type type;
Popup() {
this(null, null, Type.INPUT);
}
Popup(String title, String message, Type type) {
super();
this.message = message;
this.type = type;
setTitle(title);
setWidth(200);
setHeight(150);
setResizable(false);
initModality(Modality.WINDOW_MODAL);
}
private void initComponents(Type messageType) {
final Scene scene = new Scene(new Group());
scene.setFill(Color.WHITESMOKE);
final Label messageText = new Label(message);
final Button okayButton = new Button("Okay");
final VBox box = new VBox();
messageText.setAlignment(Pos.CENTER);
messageText.setTextAlignment(TextAlignment.CENTER);
messageText.setWrapText(true);
okayButton.setAlignment(Pos.CENTER);
okayButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
close();
}
});
String messageClass = "";
switch (messageType) {
case MESSAGE:
messageClass = "";
box.setPadding(new Insets(10, 0, 0, 0));
break;
case WARNING:
messageClass = "warning-";
box.setPadding(new Insets(10, 0, 0, 0));
break;
case ERROR:
messageClass = "error-";
box.setPadding(new Insets(30, 0, 0, 0));
break;
default:
break;
}
scene.getStylesheets().add(
"edu/wpi/first/tableviewer/stylesheets/PopupCSS.css");
messageText.getStyleClass().add(messageClass + "message");
box.setPrefWidth(200);
box.setSpacing(15);
box.setAlignment(Pos.CENTER);
box.getChildren().addAll(messageText, okayButton);
((Group) scene.getRoot()).getChildren().addAll(box);
setScene(scene);
}
@Override
public void initComponents() {
initComponents(type);
}
@Override
public void showPopup() {
initComponents();
showAndWait();
}
}

View File

@@ -0,0 +1,65 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
import edu.wpi.first.tableviewer.popup.IPopup.Type;
import edu.wpi.first.tableviewer.popup.AddValuePopup.InputType;
import edu.wpi.first.tableviewer.treeview.TableLeaf;
import edu.wpi.first.wpilibj.tables.ITable;
/**
* A factory for creating and showing {@link Popup Popups} of a defined type.
* @author Sam
*/
public final class PopupFactory {
public static void showMessageDialog(String title, String message) {
IPopup popup = new Popup(title, message, Type.MESSAGE);
popup.showPopup();
}
public static void showMessageDialog(String message) {
showMessageDialog("", message);
}
public static void showWarningDialog(String title, String message) {
IPopup popup = new Popup(title, message, Type.WARNING);
popup.showPopup();
}
public static void showWarningDialog(String message) {
showWarningDialog("", message);
}
public static void showErrorDialog(String title, String message) {
IPopup popup = new Popup(title, message, Type.ERROR);
popup.showPopup();
}
public static void showErrorDialog(String message) {
showErrorDialog("", message);
}
public static void showAddBooleanDialog(ITable table) {
IPopup popup = new AddValuePopup(table, InputType.BOOLEAN);
popup.showPopup();
}
public static void showAddNumberDialog(ITable table) {
IPopup popup = new AddValuePopup(table, InputType.NUMBER);
popup.showPopup();
}
public static void showAddStringDialog(ITable table) {
IPopup popup = new AddValuePopup(table, InputType.STRING);
popup.showPopup();
}
public static void showEditorDialog(TableLeaf leaf) {
IPopup popup = new EditorPopup(leaf);
popup.showPopup();
}
}

View File

@@ -0,0 +1,136 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.popup;
import edu.wpi.first.tableviewer.NetworkTableViewer;
import edu.wpi.first.tableviewer.treeview.TableTreeView;
import edu.wpi.first.wpilibj.networktables2.NetworkTableNode;
import edu.wpi.first.wpilibj.networktables2.client.NetworkTableClient;
import edu.wpi.first.wpilibj.networktables2.server.NetworkTableServer;
import edu.wpi.first.wpilibj.networktables2.stream.SocketStreams;
import java.io.IOException;
import java.util.prefs.Preferences;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.WindowEvent;
/**
*
* @author Sam
*/
public class PreferencesPopup extends Popup {
public static final int DEFAULT_PORT = 1735;
private final Preferences prefs = Preferences.userNodeForPackage(NetworkTableViewer.class);
private String host = "localhost";
private NetworkTableNode node;
public PreferencesPopup() {
super("Preferences", null, null);
setWidth(215);
setHeight(160);
}
public NetworkTableNode getNode() {
return node;
}
@Override
public void initComponents() {
try {
host = prefs.get("host", "localhost");
} catch (NullPointerException e) {
host = "localhost";
}
final Scene scene = new Scene(new Group());
scene.getStylesheets().add("edu/wpi/first/tableviewer/stylesheets/ViewerStyleSheet.css");
final Label hostLabel = new Label("Host:");
final CheckBox clientBox = new CheckBox("Client");
clientBox.setSelected(true); // default to client
final TextField hostField = new TextField("localhost");
final Button okayButton = new Button("OK");
final Button cancelButton = new Button("Cancel");
hostField.setMaxWidth(100);
hostField.setPromptText("Host");
hostField.setText(prefs.get("host", "localhost"));
okayButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
try {
host = hostField.getText();
if (clientBox.isSelected()) { // client
setClient(host, DEFAULT_PORT);
System.out.println("Connecting client to " + host + ":" + DEFAULT_PORT);
} else { // server
setServer(DEFAULT_PORT);
System.out.println("Starting server on port " + DEFAULT_PORT);
}
TableTreeView.setRootNode(node);
prefs.put("host", host);
close();
} catch (NumberFormatException ex) { // invalid team number
PopupFactory.showErrorDialog("Invalid team number!");
} catch (IOException ex) {
System.err.println("Error creating table node: "
+ ex.getClass().toString().substring(ex.getClass().toString().lastIndexOf(".") + 1) + ": "
+ ex.getMessage());
}
}
});
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
System.exit(0);
}
});
setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent t) {
System.exit(0);
}
});
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(5);
grid.add(clientBox, 1, 1);
grid.add(hostLabel, 1, 2);
grid.add(hostField, 2, 2);
grid.add(okayButton, 1, 3);
grid.add(cancelButton, 2, 3);
((Group) scene.getRoot()).getChildren().addAll(grid);
setScene(scene);
}
private void setServer(int port) throws IOException {
this.node = new NetworkTableServer(SocketStreams.newStreamProvider(port));
}
private void setClient(String host, int port) throws IOException {
this.node = new NetworkTableClient(SocketStreams.newStreamFactory(host, port));
((NetworkTableClient)node).reconnect();
}
}

View File

@@ -0,0 +1,32 @@
/*
Document : ErrorMessageCSS
Created on : Apr 23, 2013, 4:23:41 PM
Author : Sam
Description:
Purpose of the stylesheet follows.
*/
root {
display: block;
-fx-font-family: "Trebuchet MS";
-fx-background: #000000;
}
.message {
-fx-text-fill: #000000; /* black */
-fx-font-size: 14pt;
-fx-font-weight: bold;
}
.warning-message {
-fx-text-fill: #FF5500; /* yellow */
-fx-font-size: 14pt;
-fx-font-weight: bold;
}
/* Might need to change this*/
.error-message {
-fx-text-fill: #CC0000; /* red */
-fx-font-size: 14pt;
-fx-font-weight: bold;
}

View File

@@ -0,0 +1,71 @@
root {
display: block;
-fx-font-family: "Trebuchet MS";
}
.button {
-fx-text-fill: #111111;
-fx-border-color: #000000;
-fx-background-color: linear-gradient(#DDDDDD, #AAAAAA);
-fx-border-radius: 5;
-fx-padding: 3 6 6 6;
}
.button:hover {
-fx-background-color: linear-gradient(#FFFFFF, #CCCCCC);
}
.button:focused {
-fx-background-color: linear-gradient(#FFFFFF, #CCCCCC);
}
.combo-box {
-fx-text-fill: #111111;
-fx-border-color: #000000;
-fx-background-color: linear-gradient(#DDDDDD, #AAAAAA);
-fx-border-radius: 5;
}
.combo-box:focused {
-fx-background-color: linear-gradient(#FFFFFF, #CCCCCC);
}
.text-field {
-fx-text-fill: #111111;
-fx-prompt-text-fill: #444444;
-fx-border-color: #000000;
-fx-background-color: #CCCCCC;
-fx-border-radius: 5;
}
.text-field:focused {
-fx-background-color: #EEEEEE;
}
.scroll-bar .track{
-fx-background-color: #EFEFEF;
}
.scroll-bar .thumb {
-fx-background-color: linear-gradient(to right, #AAAAAA, #CCCCCC);
-fx-border-radius: 5;
}
.tree-cell {
-fx-font: 12pt "Trebuchet MS";
-fx-text-fill: #111111;
-fx-border-color: #DDDDFF;
}
.tree-cell:selected:focused {
-fx-background-color: #CCCCCC;
}
.tree-cell:odd {
-fx-background-color: rgb(240,240,255);
}
.tree-cell:even {
-fx-background-color: rgb(255,255,255);
}

View File

@@ -0,0 +1,24 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.treeview;
import javafx.scene.control.TreeItem;
/**
*
* @author Sam
*/
public abstract class ITableItem extends TreeItem<TreeItem> {
public ITableItem() {
super();
}
@Override
public abstract String toString();
@Override
public abstract boolean isLeaf();
}

View File

@@ -0,0 +1,119 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.treeview;
import edu.wpi.first.wpilibj.networktables.NetworkTableProvider;
import edu.wpi.first.wpilibj.networktables2.NetworkTableNode;
import edu.wpi.first.wpilibj.tables.ITable;
import edu.wpi.first.wpilibj.tables.ITableListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.TreeItem;
/**
* A {@link TreeItem} responsible for displaying all the data within a certain
* {@link ITable}. It can contain {@link TableLeaf TableLeaves} and other
* {@code TableBranches} if there are subtables in the given {@code ITable}.
*
* @see TableLeaf
* @author Sam
*/
public class TableBranch extends ITableItem implements ITableListener {
/**
* Keeps track of values in the table.
*/
private HashMap<String, ITableItem> entries = new HashMap<>();
private final ITable table;
/**
* Constructs a TableBranch that displays data from the given ITable.
*
* @param table The ITable to show the data of.
*/
public TableBranch(final ITable table) {
super();
this.table = table;
table.addTableListener(this, true);
table.addSubTableListener(this);
setExpanded(true);
setValue(this);
expandedProperty().bind(new SimpleBooleanProperty(true)); //REMOVEME
}
/**
* This should only be called once, when making the root TableBranch.
*
* @param node The root node to listen to. Sibling or parent nodes, if they
* exist, will be ignored.
* @see TableBranch(ITable)
*/
public TableBranch(NetworkTableNode node) {
this(new NetworkTableProvider(node).getRootTable());
}
@Override
public void valueChanged(ITable source, String key, Object value, boolean isNew) {
if (isNew && !entries.containsKey(key)) {
if (value.toString().startsWith("NetworkTable: /")) {
String tableName = value.toString().substring(source.toString().length() + 1);
TableBranch branch = new TableBranch(source.getSubTable(tableName));
this.getChildren().add(branch);
entries.put(key, branch);
} else {
TableLeaf leaf = new TableLeaf(source, key, value);
entries.put(key, leaf);
this.getChildren().add(leaf);
this.getChildren().removeAll(getLeaves());
this.getChildren().addAll(sortLeaves(getLeaves()));
}
} else if (!isNew && entries.get(key) instanceof TableLeaf) {
((TableLeaf) entries.get(key)).setTableValue(value);
}
}
/**
* Sorts
*
* @param leaves
* @return
*/
private List<TableLeaf> sortLeaves(List<TableLeaf> leaves) {
List<TableLeaf> list = leaves.subList(0, leaves.size());
System.out.print(leaves + "->" + list + "\t");
Collections.sort(list);
System.out.println(list);
return list;
}
private List<TableLeaf> getLeaves() {
List<TableLeaf> leaves = new ArrayList<>();
for (ITableItem item : entries.values()) {
if (item instanceof TableLeaf) {
leaves.add((TableLeaf) item);
}
}
return leaves;
}
public ITable getTable() {
return table;
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public String toString() {
return table.toString().substring(table.toString().lastIndexOf("/") + 1);
}
}

View File

@@ -0,0 +1,102 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.treeview;
import edu.wpi.first.wpilibj.tables.ITable;
/**
*
* @author Sam
*/
public class TableLeaf extends ITableItem implements Comparable {
private final ITable table;
private String entryKey;
private Object entryValue;
private EntryType entryType = EntryType.UNSUPPORTED;
@Override
public int compareTo(Object o) {
return this.getTableKey().toLowerCase().compareTo(((TableLeaf)o).getTableKey().toLowerCase());
}
public enum EntryType {
BOOLEAN, NUMBER, STRING, UNSUPPORTED
}
public TableLeaf(ITable table, String key, Object value) {
super();
this.table = table;
this.entryKey = key;
this.entryValue = value;
this.entryType = getTypeFromValue(value);
setValue(this);
}
public ITable getTable() {
return table;
}
public String getTableKey() {
return entryKey;
}
public Object getTableValue() {
return entryValue;
}
/**
* Sets the display value of this TableLeaf to a new value.
*
* @param newValue The new value of this leaf.
*/
public void setTableValue(Object newValue) {
entryValue = newValue;
entryType = getTypeFromValue(newValue);
setValue(null);
setValue(this);
}
private EntryType getTypeFromValue(Object value) {
String valueClassName = value.getClass().toString().substring(value.getClass().toString().lastIndexOf(".") + 1);
switch (valueClassName.toLowerCase()) {
case "boolean":
return EntryType.BOOLEAN;
case "double":
return EntryType.NUMBER;
case "string":
return EntryType.STRING;
default:
return EntryType.UNSUPPORTED;
}
}
/**
* Updates the value in this TableLeaf's ITable and updates the displayed
* value.
*
* @param newValue The new value of this entry.
* @see #setTableValue
*/
public void updateValue(Object newValue) {
setTableValue(newValue);
table.putValue(entryKey, entryValue);
}
public EntryType getType() {
return entryType;
}
@Override
public String toString() {
return entryKey + " = " + entryValue;
}
@Override
public boolean isLeaf() {
return true;
}
}

View File

@@ -0,0 +1,143 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.treeview;
import edu.wpi.first.tableviewer.popup.PopupFactory;
import edu.wpi.first.tableviewer.treeview.TableLeaf.EntryType;
import java.util.ArrayList;
import java.util.List;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeCell;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
/**
*
* @author Sam
*/
public class TableTreeCell extends TreeCell<ITableItem> {
private GridPane grid = new GridPane();
private Label key = new Label(),
value = new Label(),
type = new Label();
// Very hackish but it almost works. Just don't collapse tables.
// I blame JavaFX/Patrick for making me do this.
private static List<TableTreeCell> cells = new ArrayList<>();
private static int currentCell = 0;
private static int maxCells = 200;
static {
for (int i = 0; i < maxCells; i++) {
cells.add(new TableTreeCell());
}
}
public static TableTreeCell getCell() {
if (currentCell >= maxCells) {
currentCell = 0;
}
return cells.get(currentCell++);
}
private TableTreeCell() {
super();
genGrid();
this.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
ITableItem selected = getItem();
if (selected instanceof TableLeaf && t.getClickCount() == 2) {
TableLeaf leaf = (TableLeaf) selected;
PopupFactory.showEditorDialog(leaf);
}
}
});
}
private void genGrid() {
key.setPrefWidth(50);
value.setPrefWidth(125);
type.setPrefWidth(75);
grid.add(key, 0, 0);
grid.add(value, 1, 0);
grid.add(type, 2, 0);
grid.setHgap(15);
}
@Override
public void updateItem(ITableItem tableItem, boolean empty) {
super.updateItem(tableItem, empty);
if (tableItem != null && !empty) {
if (tableItem instanceof TableBranch) {
setContextMenu(getBranchMenu((TableBranch) tableItem));
setText(tableItem.toString());
setGraphic(null);
} else if (tableItem instanceof TableLeaf) {
TableLeaf leaf = (TableLeaf) tableItem;
key.setText(leaf.getTableKey());
value.setText(leaf.getTableValue().toString());
type.setText(leaf.getType().name());
setText(null);
setGraphic(grid);
setContextMenu(getLeafMenu(leaf));
}
}
}
private ContextMenu getBranchMenu(final TableBranch branch) {
MenuItem addBoolean = new MenuItem("Add boolean");
MenuItem addNumber = new MenuItem("Add number");
MenuItem addString = new MenuItem("Add string");
addBoolean.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
PopupFactory.showAddBooleanDialog(branch.getTable());
}
});
addNumber.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
PopupFactory.showAddNumberDialog(branch.getTable());
}
});
addString.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
PopupFactory.showAddStringDialog(branch.getTable());
}
});
ContextMenu cMenu = new ContextMenu();
cMenu.getItems().addAll(addBoolean, addNumber, addString);
return cMenu;
}
private ContextMenu getLeafMenu(final TableLeaf leaf) {
MenuItem edit = new MenuItem("Edit");
edit.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
PopupFactory.showEditorDialog(leaf);
}
});
ContextMenu cMenu = new ContextMenu(edit);
return cMenu;
}
}

View File

@@ -0,0 +1,74 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.wpi.first.tableviewer.treeview;
import edu.wpi.first.wpilibj.networktables2.NetworkTableNode;
import edu.wpi.first.wpilibj.networktables2.server.NetworkTableServer;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
/**
*
* @author Sam
*/
public class TableTreeView extends Stage {
private TreeView<ITableItem> tree;
private static NetworkTableNode rootNode;
public static void setRootNode(NetworkTableNode node) {
rootNode = node;
}
public TableTreeView(NetworkTableNode node) {
Scene scene = initTree();
setTitle("Network Table Viewer " + ((node instanceof NetworkTableServer) ? "Server" : "Client"));
setMinHeight(500);
setMinWidth(360);
setScene(scene);
setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent t) {
// network tables keep the application running, so exit
System.exit(0);
}
});
}
private Scene initTree() {
Scene scene = new Scene(new Group());
scene.getStylesheets().add("edu/wpi/first/tableviewer/stylesheets/ViewerStyleSheet.css");
TableBranch rootBranch = new TableBranch(rootNode); // create a branch to show the entire contents of the node
TreeItem<TreeItem> root = new TreeItem<>();
root.getChildren().add(rootBranch);
tree = new TreeView(root);
tree.setShowRoot(false);
tree.prefWidthProperty().bind(scene.widthProperty());
tree.prefHeightProperty().bind(scene.heightProperty());
tree.setCellFactory(new Callback<TreeView<ITableItem>, TreeCell<ITableItem>>() {
int calls = 0;
@Override
public TreeCell<ITableItem> call(TreeView<ITableItem> p) {
// System.out.println(++calls);
return TableTreeCell.getCell();
}
});
((Group) scene.getRoot()).getChildren().add(tree);
return scene;
}
}