diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b055b853f4..180bb28806 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -95,18 +95,18 @@ jobs:
sudo apt install -y protobuf-compiler
- name: Build
- run: mvn -Dgpg.skip=true --batch-mode install
+ run: mvn -Dgpg.skip=true -Dmaven.javadoc.skip=true --batch-mode install
- name: Publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: mvn -Dgpg.skip=true --batch-mode -DskipTests deploy
+ run: mvn -Dgpg.skip=true -Dmaven.javadoc.skip=true --batch-mode -DskipTests deploy
if: ${{ github.repository == 'ControlSystemStudio/phoebus' && (github.ref == 'refs/heads/master' || github.ref == 'refs/tags/*') }}
- name: Coveralls report
env:
COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
run: |
- mvn install jacoco:report coveralls:report -DrepoToken=$COVERALLS_TOKEN
+ mvn install -Dmaven.javadoc.skip=true jacoco:report coveralls:report -DrepoToken=$COVERALLS_TOKEN
- name: Download Coverity Build Tool
env:
@@ -120,7 +120,7 @@ jobs:
TOKEN: ${{ secrets.COVERITY_TOKEN }}
run: |
export PATH=`pwd`/cov-analysis-linux64/bin:$PATH
- cov-build --dir cov-int mvn -Dgpg.skip=true -DskipTests install
+ cov-build --dir cov-int mvn -Dgpg.skip=true -Dmaven.javadoc.skip=true -DskipTests install
- name: Submit static analysis results
env:
TOKEN: ${{ secrets.COVERITY_TOKEN }}
diff --git a/.github/workflows/nightly_linux.yml b/.github/workflows/nightly_linux.yml
index 5207e60e33..224868d743 100644
--- a/.github/workflows/nightly_linux.yml
+++ b/.github/workflows/nightly_linux.yml
@@ -19,7 +19,7 @@ jobs:
java-version: 11
- name: Build
- run: mvn -Djavafx.platform=linux -DskipTests -T6 verify
+ run: mvn -Djavafx.platform=linux -Dmaven.javadoc.skip=true -DskipTests -T6 verify
- name: Tag Repo
uses: richardsimko/update-tag@v1
@@ -32,18 +32,19 @@ jobs:
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
- tag: Commander-nightly-build # This may also be of the form 'refs/tags/staging'
+ tag: Commander-nightly-build-* # This may also be of the form 'refs/tags/staging'
assets: '*nightly-linux-x86_64.zip'
fail-if-no-release: false
fail-if-no-assets: false
- name: Upload binaries to release
- uses: svenstaro/upload-release-action@2.2.1
+ uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: phoebus-product/target/product-4.6.10-SNAPSHOT.zip
asset_name: Commander_${{github.sha}}-SNAPSHOT-nightly-linux-x86_64.zip
- tag: Commander-nightly-build
+ tag: Commander-nightly-build-${{github.sha}}
+ target_commit: ${{github.sha}}
overwrite: true
body: "Latest and greatest nightly build. This is NOT a stable version."
diff --git a/.github/workflows/nightly_mac.yml b/.github/workflows/nightly_mac.yml
index 6ae2231c0c..c8c400d71c 100644
--- a/.github/workflows/nightly_mac.yml
+++ b/.github/workflows/nightly_mac.yml
@@ -15,24 +15,25 @@ jobs:
java-version: 11
- name: Build
- run: mvn -Djavafx.platform=mac -DskipTests -T6 verify
+ run: mvn -Djavafx.platform=mac -Dmaven.javadoc.skip=true -DskipTests -T6 verify
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
- tag: Commander-nightly-build # This may also be of the form 'refs/tags/staging'
+ tag: Commander-nightly-build-* # This may also be of the form 'refs/tags/staging'
assets: '*nightly-mac-x86_64.zip'
fail-if-no-release: false
fail-if-no-assets: false
- name: Upload binaries to release
- uses: svenstaro/upload-release-action@2.2.1
+ uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: phoebus-product/target/product-4.6.10-SNAPSHOT.zip
asset_name: Commander_${{github.sha}}-SNAPSHOT-nightly-mac-x86_64.zip
- tag: Commander-nightly-build
+ tag: Commander-nightly-build-${{github.sha}}
+ target_commit: ${{github.sha}}
overwrite: true
body: "Latest and greatest nightly build. This is NOT a stable version."
diff --git a/.github/workflows/nightly_windows.yml b/.github/workflows/nightly_windows.yml
index d8ed6cb3ec..179d2a39da 100644
--- a/.github/workflows/nightly_windows.yml
+++ b/.github/workflows/nightly_windows.yml
@@ -15,24 +15,25 @@ jobs:
java-version: 11
- name: Build
- run: mvn -Djavafx.platform=win -DskipTests -T6 verify
+ run: mvn -Djavafx.platform=win -Dmaven.javadoc.skip=true -DskipTests -T6 verify
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
- tag: Commander-nightly-build # This may also be of the form 'refs/tags/staging'
+ tag: Commander-nightly-build-* # This may also be of the form 'refs/tags/staging'
assets: '*nightly-windows-x86_64.zip'
fail-if-no-release: false
fail-if-no-assets: false
- name: Upload binaries to release
- uses: svenstaro/upload-release-action@2.2.1
+ uses: svenstaro/upload-release-action@2.7.0
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: phoebus-product/target/product-4.6.10-SNAPSHOT.zip
asset_name: Commander_${{github.sha}}-SNAPSHOT-nightly-windows-x86_64.zip
- tag: Commander-nightly-build
+ tag: Commander-nightly-build-${{github.sha}}
+ target_commit: ${{github.sha}}
overwrite: true
body: "Latest and greatest nightly build. This is NOT a stable version."
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..ad4e5d18d2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+build:
+ mvn -DskipTests install -T6
diff --git a/app/commander/app-commander-command-options/.classpath b/app/commander/app-commander-command-options/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-command-options/.classpath
+++ b/app/commander/app-commander-command-options/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-command-options/pom.xml b/app/commander/app-commander-command-options/pom.xml
index 71cd951a2d..11649e2454 100644
--- a/app/commander/app-commander-command-options/pom.xml
+++ b/app/commander/app-commander-command-options/pom.xml
@@ -5,7 +5,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-command-options
@@ -50,7 +50,7 @@
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
junit
diff --git a/app/commander/app-commander-connections/.classpath b/app/commander/app-commander-connections/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-connections/.classpath
+++ b/app/commander/app-commander-connections/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-connections/pom.xml b/app/commander/app-commander-connections/pom.xml
index 8f5816f564..987a5bc4aa 100644
--- a/app/commander/app-commander-connections/pom.xml
+++ b/app/commander/app-commander-connections/pom.xml
@@ -3,7 +3,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-connections
@@ -48,13 +48,13 @@
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
test-jar
test
diff --git a/app/commander/app-commander-display-model/.classpath b/app/commander/app-commander-display-model/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-display-model/.classpath
+++ b/app/commander/app-commander-display-model/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-display-model/pom.xml b/app/commander/app-commander-display-model/pom.xml
index 4c8a4fb0cf..9c76c3e477 100644
--- a/app/commander/app-commander-display-model/pom.xml
+++ b/app/commander/app-commander-display-model/pom.xml
@@ -3,7 +3,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-display-model
diff --git a/app/commander/app-commander-display-representation-javafx/.classpath b/app/commander/app-commander-display-representation-javafx/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-display-representation-javafx/.classpath
+++ b/app/commander/app-commander-display-representation-javafx/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-display-representation-javafx/pom.xml b/app/commander/app-commander-display-representation-javafx/pom.xml
index 1095485227..d511c166c9 100644
--- a/app/commander/app-commander-display-representation-javafx/pom.xml
+++ b/app/commander/app-commander-display-representation-javafx/pom.xml
@@ -3,13 +3,13 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-display-model
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-display-representation-javafx
diff --git a/app/commander/app-commander-display-runtime/.classpath b/app/commander/app-commander-display-runtime/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-display-runtime/.classpath
+++ b/app/commander/app-commander-display-runtime/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-display-runtime/pom.xml b/app/commander/app-commander-display-runtime/pom.xml
index ce9e7cfe08..8470877bbd 100644
--- a/app/commander/app-commander-display-runtime/pom.xml
+++ b/app/commander/app-commander-display-runtime/pom.xml
@@ -3,13 +3,13 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-display-model
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-display-runtime
diff --git a/app/commander/app-commander-events/.classpath b/app/commander/app-commander-events/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-events/.classpath
+++ b/app/commander/app-commander-events/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-events/pom.xml b/app/commander/app-commander-events/pom.xml
index 66a62a24cb..8814396c0d 100644
--- a/app/commander/app-commander-events/pom.xml
+++ b/app/commander/app-commander-events/pom.xml
@@ -5,7 +5,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-events
@@ -50,7 +50,7 @@
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
junit
diff --git a/app/commander/app-commander-links/Makefile b/app/commander/app-commander-links/Makefile
new file mode 100644
index 0000000000..b1173ee1fa
--- /dev/null
+++ b/app/commander/app-commander-links/Makefile
@@ -0,0 +1,2 @@
+format:
+ mvn com.coveo:fmt-maven-plugin:format
diff --git a/app/commander/app-commander-links/pom.xml b/app/commander/app-commander-links/pom.xml
new file mode 100644
index 0000000000..295f646dc5
--- /dev/null
+++ b/app/commander/app-commander-links/pom.xml
@@ -0,0 +1,92 @@
+
+ 4.0.0
+
+ com.windhoverlabs
+ app-commander
+ 0.2.6-SNAPSHOT
+
+ app-commander-links
+
+
+
+ sphinx
+
+
+
+ org.apache.maven.plugins
+ maven-site-plugin
+ 3.7.1
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+ 3.0.0
+
+
+
+ kr.motd.maven
+ sphinx-maven-plugin
+ 2.10.0
+
+ ${basedir}/docs/source
+ ${basedir}/docs/build/html
+
+
+
+ package
+
+ generate
+
+
+
+
+
+
+
+
+
+
+ com.windhoverlabs
+ commander-core
+ 0.2.6-SNAPSHOT
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
+
+ org.testfx
+ testfx-core
+ 4.0.13-alpha
+ test
+
+
+ org.testfx
+ testfx-junit
+ 4.0.13-alpha
+ test
+
+
+ org.w3c
+ dom
+ 2.3.0-jaxb-1.0.6
+
+
+
+ org.yamcs
+ yamcs-api
+
+ 5.7.9
+
+
+
\ No newline at end of file
diff --git a/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerApp.java b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerApp.java
new file mode 100644
index 0000000000..46fdc2216f
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerApp.java
@@ -0,0 +1,56 @@
+package com.windhoverlabs.yamcs.applications.links;
+
+import java.nio.file.Path;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.phoebus.framework.preferences.AnnotatedPreferences;
+import org.phoebus.framework.preferences.Preference;
+import org.phoebus.framework.spi.AppDescriptor;
+import org.phoebus.framework.spi.AppInstance;
+
+@SuppressWarnings("nls")
+public class LinksViewerApp implements AppDescriptor {
+
+ public static final String Name = "Links";
+
+ public static final String DisplayName = Messages.DisplayName;
+
+ public static final Logger log = Logger.getLogger(LinksViewerApp.class.getPackageName());
+
+ @Preference public static String css_path;
+
+ static {
+ AnnotatedPreferences.initialize(LinksViewerApp.class, "/eventviewer_preferences.properties");
+ }
+
+ @Override
+ public String getName() {
+ return Name;
+ }
+
+ public static String getCSSPath() {
+ String path = css_path.trim();
+ if (path.isEmpty()) {
+ return LinksViewerInstance.class.getResource("/events_style.css").toExternalForm();
+ } else {
+ return Path.of(path).toUri().toString();
+ }
+ }
+
+ @Override
+ public AppInstance create() {
+
+ if (LinksViewerInstance.INSTANCE == null) {
+ try {
+ LinksViewerInstance.INSTANCE = new LinksViewerInstance(this);
+ } catch (Exception ex) {
+ Logger.getLogger(LinksViewerApp.class.getPackageName())
+ .log(Level.WARNING, "Cannot create Error Log", ex);
+ return null;
+ }
+ } else {
+ LinksViewerInstance.INSTANCE.raise();
+ }
+ return LinksViewerInstance.INSTANCE;
+ }
+}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportController.java b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerController.java
similarity index 51%
rename from app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportController.java
rename to app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerController.java
index 6d98054599..e330e6ed84 100644
--- a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportController.java
+++ b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerController.java
@@ -1,4 +1,4 @@
-package com.windhoverlabs.yamcs.applications.events;
+package com.windhoverlabs.yamcs.applications.links;
import com.windhoverlabs.pv.yamcs.YamcsAware;
import com.windhoverlabs.yamcs.core.CMDR_Event;
@@ -7,12 +7,15 @@
import java.text.DecimalFormat;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
+import javafx.css.SimpleStyleableStringProperty;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.TableCell;
@@ -21,15 +24,29 @@
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
+import javafx.scene.shape.Circle;
import org.yamcs.protobuf.Event.EventSeverity;
-public class ParameterExportController {
- public static final Logger log = Logger.getLogger(ParameterExportController.class.getPackageName());
+public class LinksViewerController {
+ public static final Logger log = Logger.getLogger(LinksViewerController.class.getPackageName());
- private final TableView tableView = new TableView();
+ private final TableView tableView =
+ new TableView();
- TableColumn messageCol = new TableColumn("Message");
+ TableColumn inCount =
+ new TableColumn("In");
+ TableColumn annotationCol = new TableColumn();
+ TableColumn generationTimeCol =
+ new TableColumn("Generation Time");
+ TableColumn receptionTimeCol =
+ new TableColumn("Reception Time");
+ TableColumn nameCol =
+ new TableColumn("Name");
TableColumn typeCol = new TableColumn("Type");
+ TableColumn sourceCol = new TableColumn("Source");
+ TableColumn instanceCol = new TableColumn("Instance");
+
+ private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ObservableList data =
FXCollections.observableArrayList(new ArrayList());
@@ -51,15 +68,29 @@ public Node getRootPane() {
@FXML
public void initialize() {
- tableView.setId("eventsTable");
- messageCol.setCellValueFactory(
- (event) -> {
- return new SimpleStringProperty(event.getValue().getMessage());
+ tableView.setId("LinksTable");
+
+ // scheduler.scheduleAtFixedRate(
+ // () -> {
+ // // this.outOfSync = this.logEventCount != this.streamEventCount;
+ //// tableView.refresh();
+ // },
+ // 30,
+ // 30,
+ // TimeUnit.SECONDS);
+ // tableView.getStylesheets().add(LinksViewerApp.getCSSPath());
+ nameCol.setCellValueFactory(
+ (link) -> {
+ SimpleStyleableStringProperty s = new javafx.css.SimpleStyleableStringProperty(null);
+ if (link != null && link.getValue() != null) {
+ s.set(link.getValue().getName());
+ }
+ return s;
});
- messageCol.setCellFactory(
+ nameCol.setCellFactory(
column -> {
- return new TableCell() {
+ return new TableCell() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty); // This is mandatory
@@ -69,43 +100,75 @@ protected void updateItem(String item, boolean empty) {
setStyle("");
} else { // If the cell is not empty
// We get here all the info of the event of this row
- CMDR_Event event = getTableView().getItems().get(getIndex());
- switch (event.getSeverity()) {
- case CRITICAL:
- this.getStyleClass().add("critical");
- break;
- case DISTRESS:
- this.getStyleClass().add("distress");
- break;
- case ERROR:
- this.getStyleClass().add("error");
- break;
- case INFO:
- this.getStyleClass().add("info");
- break;
- case SEVERE:
- this.getStyleClass().add("severe");
- break;
- case WARNING:
- this.getStyleClass().add("warning");
- break;
- case WATCH:
- this.getStyleClass().add("watch");
- break;
- default:
- setTextFill(Color.BLACK);
- break;
- }
+ // CMDR_Event event = getTableView().getItems().get(getIndex());
+ // switch (event.getSeverity()) {
+ // case CRITICAL:
+ // this.getStyleClass().add("critical");
+ // break;
+ // case DISTRESS:
+ // this.getStyleClass().add("distress");
+ // break;
+ // case ERROR:
+ // this.getStyleClass().add("error");
+ // break;
+ // case INFO:
+ // this.getStyleClass().add("info");
+ // break;
+ // case SEVERE:
+ // this.getStyleClass().add("severe");
+ // break;
+ // case WARNING:
+ // this.getStyleClass().add("warning");
+ // break;
+ // case WATCH:
+ // this.getStyleClass().add("watch");
+ // break;
+ // default:
+ // setTextFill(Color.BLACK);
+ // break;
+ // }
setText(item); // Put the String data in the cell
+ Circle circle = new Circle();
+ circle.setCenterX(100.0f);
+ circle.setCenterY(100.0f);
+ circle.setRadius(10.0f);
+ var activeColor = Color.RED;
+ if (YamcsObjectManager.getDefaultInstance() != null
+ && YamcsObjectManager.getDefaultInstance().getLinksMap().get(item) != null) {
+ if (YamcsObjectManager.getDefaultInstance().isLinkActive(item)) {
+ activeColor = Color.LIGHTGREEN;
+ } else {
+ // activeColor = activeColor.darker();
+ activeColor = Color.BLUE;
+ }
+ }
+
+ circle.setFill(activeColor);
+ this.setGraphic(circle);
}
}
};
});
- tableView
- .getColumns()
- .addAll(
- messageCol,
- typeCol);
+ inCount.setCellValueFactory(
+ (link) -> {
+ if (link != null && link.getValue() != null) {
+ return new SimpleStringProperty(Long.toString(link.getValue().getDataInCount()));
+ } else {
+ return new SimpleStringProperty("");
+ }
+ });
+ // tableView
+ // .getColumns()
+ // .addAll(
+ // nameCol,
+ // generationTimeCol,
+ // receptionTimeCol,
+ // severityCol,
+ // typeCol,
+ // sourceCol,
+ // instanceCol);
+
+ tableView.getColumns().addAll(nameCol, inCount);
yamcsListener =
new YamcsAware() {
@@ -124,7 +187,7 @@ public void onChanged(Change> c) {
});
}
});
- tableView.setItems(YamcsObjectManager.getDefaultInstance().getEvents());
+ tableView.setItems(YamcsObjectManager.getDefaultInstance().getLinks());
tableView.refresh();
}
@@ -144,7 +207,7 @@ public void onChanged(Change> c) {
});
}
});
- tableView.setItems(YamcsObjectManager.getDefaultInstance().getEvents());
+ tableView.setItems(YamcsObjectManager.getDefaultInstance().getLinks());
tableView.refresh();
}
}
@@ -165,10 +228,14 @@ public void onChanged(Change> c) {
});
}
});
- tableView.setItems(YamcsObjectManager.getDefaultInstance().getEvents());
+ tableView.setItems(YamcsObjectManager.getDefaultInstance().getLinks());
tableView.refresh();
}
}
+
+ // public void updateLink(String link) {
+ // tableView.refresh();
+ // }
};
YamcsObjectManager.addYamcsListener(yamcsListener);
@@ -181,7 +248,7 @@ public void onChanged(Change> c) {
gridPane.add(tableView, 0, 1);
}
- public ParameterExportController() {
+ public LinksViewerController() {
System.out.println("EventViewerController constructor$$$$$$$$$$$$$$");
}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportViewerInstance.java b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerInstance.java
similarity index 77%
rename from app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportViewerInstance.java
rename to app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerInstance.java
index 727a6b5781..ca53682356 100644
--- a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExportViewerInstance.java
+++ b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerInstance.java
@@ -1,4 +1,4 @@
-package com.windhoverlabs.yamcs.applications.events;
+package com.windhoverlabs.yamcs.applications.links;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -20,32 +20,28 @@
/** @author lgomez */
@SuppressWarnings("nls")
-public class ParameterExportViewerInstance implements AppInstance {
- private static final String YAMCS_EVENTS_MEMENTO_FILENAME = "yamcs_events_memento";
+public class LinksViewerInstance implements AppInstance {
/** Logger for all file browser code */
- public static final Logger logger = Logger.getLogger(ParameterExportViewerInstance.class.getPackageName());
+ public static final Logger logger = Logger.getLogger(LinksViewerInstance.class.getPackageName());
- /** Memento tags */
- private static final String YAMCS_EVENTS = "yamcs_events", YAMCS_EVENT_MESSAGE = "message";
-
- static ParameterExportViewerInstance INSTANCE;
+ static LinksViewerInstance INSTANCE;
private FXMLLoader loader;
- private ParameterExportController eventInstanceController = null;
+ private LinksViewerController eventInstanceController = null;
private final AppDescriptor app;
private DockItem tab = null;
- public ParameterExportViewerInstance(AppDescriptor app) {
+ public LinksViewerInstance(AppDescriptor app) {
this.app = app;
Node content = null;
ResourceBundle resourceBundle = NLS.getMessages(Messages.class);
FXMLLoader loader = new FXMLLoader();
loader.setResources(resourceBundle);
- loader.setLocation(this.getClass().getResource("EventView.fxml"));
+ loader.setLocation(this.getClass().getResource("LinksView.fxml"));
try {
content = loader.load();
@@ -99,7 +95,7 @@ public void raise() {
tab.select();
}
- public ParameterExportController getController() {
+ public LinksViewerController getController() {
return eventInstanceController;
}
diff --git a/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerMenuEntry.java b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerMenuEntry.java
new file mode 100644
index 0000000000..699063dd5b
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/LinksViewerMenuEntry.java
@@ -0,0 +1,30 @@
+package com.windhoverlabs.yamcs.applications.links;
+
+import javafx.scene.image.Image;
+import org.phoebus.framework.workbench.ApplicationService;
+import org.phoebus.ui.javafx.ImageCache;
+import org.phoebus.ui.spi.MenuEntry;
+
+@SuppressWarnings("nls")
+public class LinksViewerMenuEntry implements MenuEntry {
+ @Override
+ public String getName() {
+ return LinksViewerApp.Name;
+ }
+
+ @Override
+ public String getMenuPath() {
+ return Messages.MenuPath;
+ }
+
+ @Override
+ public Image getIcon() {
+ return ImageCache.getImage(LinksViewerApp.class, "/icons/filebrowser.png");
+ }
+
+ @Override
+ public Void call() throws Exception {
+ ApplicationService.createInstance(LinksViewerApp.Name);
+ return null;
+ }
+}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/Messages.java b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/Messages.java
similarity index 98%
rename from app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/Messages.java
rename to app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/Messages.java
index 2f6721422e..6956956b4c 100644
--- a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/Messages.java
+++ b/app/commander/app-commander-links/src/main/java/com/windhoverlabs/yamcs/applications/links/Messages.java
@@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
******************************************************************************/
-package com.windhoverlabs.yamcs.applications.events;
+package com.windhoverlabs.yamcs.applications.links;
import org.phoebus.framework.nls.NLS;
diff --git a/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.framework.spi.AppDescriptor b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.framework.spi.AppDescriptor
new file mode 100644
index 0000000000..db03c858da
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.framework.spi.AppDescriptor
@@ -0,0 +1 @@
+com.windhoverlabs.yamcs.applications.links.LinksViewerApp
\ No newline at end of file
diff --git a/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.MenuEntry b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.MenuEntry
new file mode 100644
index 0000000000..c27b194d41
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.MenuEntry
@@ -0,0 +1 @@
+com.windhoverlabs.yamcs.applications.links.LinksViewerMenuEntry
\ No newline at end of file
diff --git a/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.ToolbarEntry b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.ToolbarEntry
new file mode 100644
index 0000000000..c2e8342eb3
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/META-INF/services/org.phoebus.ui.spi.ToolbarEntry
@@ -0,0 +1,2 @@
+#TODO:Add Toolbar Entries
+#org.phoebus.applications.commander.connections.FileBrowserToolbarEntry
\ No newline at end of file
diff --git a/app/commander/app-commander-parameter-export/src/main/resources/com/windhoverlabs/yamcs/applications/events/EventView.fxml b/app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/LinksView.fxml
similarity index 93%
rename from app/commander/app-commander-parameter-export/src/main/resources/com/windhoverlabs/yamcs/applications/events/EventView.fxml
rename to app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/LinksView.fxml
index f2d47c3714..049a56c95e 100644
--- a/app/commander/app-commander-parameter-export/src/main/resources/com/windhoverlabs/yamcs/applications/events/EventView.fxml
+++ b/app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/LinksView.fxml
@@ -6,7 +6,7 @@
-
+
diff --git a/app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/messages.properties b/app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/messages.properties
new file mode 100644
index 0000000000..49d9f9b898
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/com/windhoverlabs/yamcs/applications/links/messages.properties
@@ -0,0 +1,47 @@
+BaseDirectorySelTT=Select a File Browser path
+BaseDirectoryTT=Enter File Browser path
+BrowserRootTitle=Select File Browser Path
+ColName=Name
+ColSize=Size
+ColTime=Time
+CopyPathClp=Copy Path to Clipboard
+CreateDirectoryErr=Cannot create new folder
+CreateDirectoryHdr=Enter name for new folder under
+Delete=Delete
+DeleteJobName=Delete
+DeletePromptHeader=Delete
+DeletePromptTitle=Delete
+DisplayName=Links
+Duplicate=Duplicate
+DuplicateAlert1=File
+DuplicateAlert2=already exists
+DuplicateJobName=Rename
+DuplicatePrefix=Copy_of_
+DuplicatePromptHeader=Enter name for duplicated file:
+HomeButtonTT=Revert to default directory
+LookupJobName=File Lookup
+MenuPath=Yamcs
+MoveOrCopyAlert=Failed to move or copy\n{0}\nto\n{1}
+MoveOrCopyAlertTitle=Move or Copy Error
+MoveOrCopyJobName=Move/copy file
+NewFolder=New Folder
+NewFolderAlert=Folder\n{0}\nalready exists
+Open=Open
+OpenAlert1=Cannot open\n
+OpenAlert2=,\nsee log for details
+OpenWith=Open With...
+Paste=Paste Files from Clipboard
+PropDlgBytes=bytes
+PropDlgDate=Date:
+PropDlgExecutable=Executable
+PropDlgPath=Path:
+PropDlgPermissions=Permissions:
+PropDlgSize=Size:
+PropDlgTitle=File Properties
+PropDlgWritable=Writeable
+Properties=Properties
+Refresh=Refresh
+Rename=Rename
+RenameHdr=Enter new name:
+RenameJobName=Rename
+SetBaseDirectory=Set as File Browser Path
diff --git a/app/commander/app-commander-links/src/main/resources/eventviewer_preferences.properties b/app/commander/app-commander-links/src/main/resources/eventviewer_preferences.properties
new file mode 100644
index 0000000000..71f0987453
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/eventviewer_preferences.properties
@@ -0,0 +1,8 @@
+# --------------------------------------------
+# Package com.windhoverlabs.commander.applications.events
+# --------------------------------------------
+
+#You may specify the CSS file used to style events here or inside of a custom settings.ini file.
+#If no path is specified, then the file at app-commander-events/src/main/resources/events_style.css
+#is used instead.
+#css_path=$(phoebus.install)/some_path
\ No newline at end of file
diff --git a/app/commander/app-commander-links/src/main/resources/icons/activate.png b/app/commander/app-commander-links/src/main/resources/icons/activate.png
new file mode 100644
index 0000000000..a2b0e676cf
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/activate.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/icons/add_server_connection.png b/app/commander/app-commander-links/src/main/resources/icons/add_server_connection.png
new file mode 100644
index 0000000000..851ea63f2e
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/add_server_connection.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/icons/delete.png b/app/commander/app-commander-links/src/main/resources/icons/delete.png
new file mode 100644
index 0000000000..5f00385852
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/delete.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/icons/fb_home.png b/app/commander/app-commander-links/src/main/resources/icons/fb_home.png
new file mode 100644
index 0000000000..9a67fd58e6
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/fb_home.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/icons/filebrowser.png b/app/commander/app-commander-links/src/main/resources/icons/filebrowser.png
new file mode 100644
index 0000000000..8e521645d8
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/filebrowser.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/icons/filebrowser@2x.png b/app/commander/app-commander-links/src/main/resources/icons/filebrowser@2x.png
new file mode 100644
index 0000000000..1d274ab9be
Binary files /dev/null and b/app/commander/app-commander-links/src/main/resources/icons/filebrowser@2x.png differ
diff --git a/app/commander/app-commander-links/src/main/resources/links_style.css b/app/commander/app-commander-links/src/main/resources/links_style.css
new file mode 100644
index 0000000000..fd0ee92c03
--- /dev/null
+++ b/app/commander/app-commander-links/src/main/resources/links_style.css
@@ -0,0 +1,28 @@
+.info {
+ -fx-text-fill: black;
+}
+
+.warning {
+ -fx-text-fill: red;
+}
+
+.error {
+ -fx-text-fill: red;
+}
+
+.watch {
+ -fx-text-fill: black;
+}
+
+.distress {
+ -fx-text-fill: black;
+}
+
+.critical {
+ -fx-text-fill: black;
+}
+
+.severe {
+ -fx-text-fill: black;
+}
+
diff --git a/app/commander/app-commander-mission-planner/.classpath b/app/commander/app-commander-mission-planner/.classpath
index 234db15be4..b010aef042 100644
--- a/app/commander/app-commander-mission-planner/.classpath
+++ b/app/commander/app-commander-mission-planner/.classpath
@@ -9,6 +9,7 @@
+
@@ -28,5 +29,12 @@
+
+
+
+
+
+
+
diff --git a/app/commander/app-commander-mission-planner/pom.xml b/app/commander/app-commander-mission-planner/pom.xml
index a0239fd439..4f64d5e9c6 100644
--- a/app/commander/app-commander-mission-planner/pom.xml
+++ b/app/commander/app-commander-mission-planner/pom.xml
@@ -3,7 +3,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-mission-planner
diff --git a/app/commander/app-commander-parameter-export/Makefile b/app/commander/app-commander-parameter-export/Makefile
new file mode 100644
index 0000000000..b1173ee1fa
--- /dev/null
+++ b/app/commander/app-commander-parameter-export/Makefile
@@ -0,0 +1,2 @@
+format:
+ mvn com.coveo:fmt-maven-plugin:format
diff --git a/app/commander/app-commander-parameter-export/pom.xml b/app/commander/app-commander-parameter-export/pom.xml
index 460bfecb91..c25d89bdb0 100644
--- a/app/commander/app-commander-parameter-export/pom.xml
+++ b/app/commander/app-commander-parameter-export/pom.xml
@@ -5,7 +5,7 @@
com.windhoverlabs
app-commander
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
app-commander-parameter-export
@@ -47,10 +47,17 @@
+
+
+ org.apache.commons
+ commons-csv
+ 1.10.0
+
+
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
junit
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportCSVJob.java b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportCSVJob.java
new file mode 100644
index 0000000000..bd57af93f7
--- /dev/null
+++ b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportCSVJob.java
@@ -0,0 +1,427 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2018 Oak Ridge National Laboratory.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package com.windhoverlabs.yamcs.applications.parameter;
+
+import com.windhoverlabs.yamcs.core.YamcsObjectManager;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import org.csstudio.trends.databrowser3.Activator;
+import org.phoebus.archive.reader.ArchiveReader;
+import org.phoebus.framework.jobs.JobMonitor;
+import org.phoebus.framework.jobs.JobRunnable;
+import org.yamcs.client.Helpers;
+import org.yamcs.client.Page;
+import org.yamcs.protobuf.Pvalue.ParameterValue;
+
+/**
+ * Base for Eclipse Job for exporting data from Model to file
+ *
+ * @author Kay Kasemir
+ */
+@SuppressWarnings("nls")
+public class ExportCSVJob implements JobRunnable {
+
+ class CountedParameterValue {
+ private ParameterValue pv;
+ int count;
+
+ public CountedParameterValue(ParameterValue pv, int count) {
+ this.pv = pv;
+ this.count = count;
+ }
+ }
+
+ public static final int PROGRESS_UPDATE_LINES = 1000;
+ public Instant start, end;
+ public String filename;
+ public Consumer error_handler;
+ public ArrayList parameters = new ArrayList();
+
+ public AtomicInteger jobBarrier = new AtomicInteger(0);
+
+ public HashMap> timeStampToParameters =
+ new HashMap>();
+ /** Active readers, used to cancel and close them */
+ private final CopyOnWriteArrayList archive_readers =
+ new CopyOnWriteArrayList();
+
+ public final boolean unixTimeStamp;
+ private CancellationPoll cancel_poll;
+
+ /**
+ * Thread that polls a progress monitor and cancels active archive readers if the user requests
+ * the export job to end via the progress monitor
+ */
+ class CancellationPoll implements Runnable {
+
+ private final JobMonitor monitor;
+ volatile boolean exit = false;
+
+ public CancellationPoll(final JobMonitor monitor) {
+ this.monitor = monitor;
+ }
+
+ @Override
+ public void run() {
+ while (!exit) {
+ if (monitor.isCanceled()) {
+ for (ArchiveReader reader : archive_readers) reader.cancel();
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * @param comment Comment prefix ('#' for most ASCII, '%' for Matlab, ...)
+ * @param model Model with data
+ * @param start Start time
+ * @param end End time
+ * @param source Where to get samples
+ * @param optimize_parameter Used by optimized source
+ * @param filename Name of file to create or null
if performExport
+ * handles the file
+ * @param error_handler Callback for errors
+ * @param unixTimeStamp If true
, time stamps are UNIX style, i.e. ms since EPOCH.
+ * Defaults to false.
+ */
+ public ExportCSVJob(
+ final Instant start,
+ final Instant end,
+ final String filename,
+ final Consumer error_handler,
+ final boolean unixTimeStamp,
+ ArrayList parameters) {
+ this.start = start;
+ this.end = end;
+ this.filename = filename;
+ this.error_handler = error_handler;
+ this.unixTimeStamp = unixTimeStamp;
+ this.parameters = parameters;
+ }
+
+ /** Job's main routine {@inheritDoc} */
+ @Override
+ public final void run(final JobMonitor monitor) {
+ monitor.beginTask("Data Export", 100);
+
+ try {
+ BufferedWriter writer;
+ if (filename != null) {
+ writer = Files.newBufferedWriter(Paths.get(filename));
+ // printExportzInfo(out);
+ } else writer = null;
+ // Start thread that checks monitor to cancels readers when
+ // user tries to abort the export job
+ cancel_poll = new CancellationPoll(monitor);
+ final Future> done = Activator.thread_pool.submit(cancel_poll);
+ performExport(monitor, writer);
+ // ask thread to exit
+ // cancel_poll.exit = true;
+ // if (writer != null) writer.close();
+ // Wait for poller to quit
+ done.get();
+ } catch (final Exception ex) {
+ error_handler.accept(ex);
+ }
+ }
+
+ /**
+ * Perform the data export
+ *
+ * @param out PrintStream for output
+ * @throws Exception on error
+ */
+ private void performExport(final JobMonitor monitor, BufferedWriter writer) {
+ monitor.worked(0);
+ YamcsObjectManager.getDefaultInstance()
+ .getParameters(
+ YamcsObjectManager.getDefaultServer().getYamcsClient(),
+ this.parameters,
+ start,
+ end,
+ (pages) -> {
+ handlePages(pages);
+ writeToCSV(writer);
+ monitor.worked(100);
+ cancel_poll.exit = true;
+ });
+ monitor.worked(10);
+ }
+
+ private void writeToCSV(BufferedWriter writer) {
+ CSVPrinter csvPrinter = null;
+ ArrayList columnHeaders = new ArrayList();
+ try {
+ columnHeaders.add("Time");
+ columnHeaders.add("RelativeTime_MS");
+
+ for (String p : this.parameters) {
+ var nameParts = p.split("/");
+ var name = nameParts[nameParts.length - 1];
+ columnHeaders.add(name);
+ columnHeaders.add(name + "_Count");
+ }
+
+ csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT);
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ cancel_poll.exit = true;
+ return;
+ }
+ try {
+ csvPrinter.printRecord(columnHeaders);
+
+ List sortedTimeStamps = new ArrayList(timeStampToParameters.keySet());
+ Collections.sort(sortedTimeStamps);
+
+ long deltaCount = 0;
+ Instant timeZero = sortedTimeStamps.get(0);
+ ArrayList recordZero = new ArrayList();
+ recordZero.add(timeZero.toString());
+ recordZero.add(Long.toString(deltaCount));
+ HashMap> zeroParamToCountMap =
+ new HashMap>();
+ for (var p : this.parameters) {
+ var nameParts = p.split("/");
+ var name = nameParts[nameParts.length - 1];
+ zeroParamToCountMap
+ .computeIfAbsent(timeZero, (instant) -> new HashMap())
+ .put(name, 0);
+ }
+ resolvePvsForRecord(timeZero, recordZero, zeroParamToCountMap, null);
+
+ csvPrinter.printRecord(recordZero);
+
+ HashMap> paramToCountMap =
+ new HashMap>();
+
+ HashMap> paramToLatestValMap =
+ new HashMap>();
+ paramToCountMap.put(timeZero, zeroParamToCountMap.entrySet().iterator().next().getValue());
+ var latestValueForParam = new HashMap();
+ for (int i = 1; i < sortedTimeStamps.size(); i++) {
+ var currentCountMap =
+ paramToCountMap.computeIfAbsent(
+ sortedTimeStamps.get(i), (item) -> new HashMap());
+ var currentLatestValMap =
+ paramToLatestValMap.computeIfAbsent(
+ sortedTimeStamps.get(i), (item) -> new HashMap());
+ for (var p : this.parameters) {
+ var nameParts = p.split("/");
+ var name = nameParts[nameParts.length - 1];
+ currentCountMap.put(name, 0);
+ var currentParam = timeStampToParameters.get(sortedTimeStamps.get(i)).get(name);
+ if (currentParam.pv != null) {
+ latestValueForParam.put(name, currentParam.pv);
+ int prevCount = paramToCountMap.get(sortedTimeStamps.get(i - 1)).get(name);
+ currentCountMap.put(name, prevCount + 1);
+ } else {
+ int prevCount = paramToCountMap.get(sortedTimeStamps.get(i - 1)).get(name);
+ currentCountMap.put(name, prevCount);
+ }
+
+ if (latestValueForParam.containsKey(name))
+ ;
+ {
+ currentLatestValMap.put(name, latestValueForParam.get(name));
+ }
+ }
+ }
+
+ for (int i = 1; i < sortedTimeStamps.size(); i++) {
+ ArrayList record = new ArrayList();
+
+ Duration zeroDelta = Duration.between(timeZero, sortedTimeStamps.get(i));
+ deltaCount = zeroDelta.toMillis();
+ record.add(sortedTimeStamps.get(i).toString());
+ record.add(Long.toString(deltaCount));
+ resolvePvsForRecord(sortedTimeStamps.get(i), record, paramToCountMap, paramToLatestValMap);
+ csvPrinter.printRecord(record);
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ csvPrinter.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Blocks until we are done processing all pages from YAMCS
+ *
+ * @param pages
+ */
+ private void handlePages(ArrayList> pages) {
+ pages.parallelStream()
+ .forEach(
+ page -> {
+ page.iterator()
+ .forEachRemaining(
+ pv -> {
+ constructTimeToParamsMap(pv);
+ });
+ while (page.hasNextPage()) {
+ try {
+ try {
+ page = page.getNextPage().get(1, TimeUnit.MINUTES);
+ } catch (TimeoutException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ } catch (InterruptedException | ExecutionException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ page.iterator()
+ .forEachRemaining(
+ pv -> {
+ constructTimeToParamsMap(pv);
+ });
+ }
+ });
+
+ while (jobBarrier.get() < pages.size()) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void resolvePvsForRecord(
+ Instant currentTimeStamp,
+ ArrayList record,
+ HashMap> currentCountMap,
+ HashMap> latestValueMap) {
+ for (var p : this.parameters) {
+ var nameParts = p.split("/");
+ var name = nameParts[nameParts.length - 1];
+ CountedParameterValue currentCountedP = timeStampToParameters.get(currentTimeStamp).get(name);
+ if (currentCountedP.pv != null) {
+ resolvePV(record, currentCountedP);
+ record.add(Integer.toString(currentCountMap.get(currentTimeStamp).get(name)));
+ } else {
+ if (latestValueMap == null || latestValueMap.get(currentTimeStamp).get(name) == null) {
+ record.add("N/A");
+ } else {
+ CountedParameterValue latestCountedP =
+ new CountedParameterValue(latestValueMap.get(currentTimeStamp).get(name), 0);
+ resolvePV(record, latestCountedP);
+ }
+ record.add(Integer.toString(currentCountMap.get(currentTimeStamp).get(name)));
+ }
+ }
+ }
+
+ private void resolvePV(ArrayList record, CountedParameterValue countedP) {
+ switch (countedP.pv.getEngValue().getType()) {
+ case AGGREGATE:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case ARRAY:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case BINARY:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case BOOLEAN:
+ record.add(Boolean.toString(countedP.pv.getEngValue().getBooleanValue()));
+ break;
+ case DOUBLE:
+ record.add(Double.toString(countedP.pv.getEngValue().getDoubleValue()));
+ break;
+ case ENUMERATED:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case FLOAT:
+ record.add(Float.toString(countedP.pv.getEngValue().getFloatValue()));
+ break;
+ case NONE:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case SINT32:
+ record.add(Integer.toString(countedP.pv.getEngValue().getSint32Value()));
+ break;
+ case SINT64:
+ record.add(Long.toString(countedP.pv.getEngValue().getSint64Value()));
+ break;
+ case STRING:
+ record.add(countedP.pv.getEngValue().getStringValue());
+ break;
+ case TIMESTAMP:
+ record.add(countedP.pv.getEngValue().getType().toString());
+ break;
+ case UINT32:
+ record.add(Integer.toString(countedP.pv.getEngValue().getUint32Value()));
+ break;
+ case UINT64:
+ record.add(Long.toString(countedP.pv.getEngValue().getUint64Value()));
+ break;
+ default:
+ record.add("Something_ELSE");
+ break;
+ }
+ }
+
+ private synchronized void constructTimeToParamsMap(ParameterValue pv) {
+ Instant pvGenerationTime = Helpers.toInstant(pv.getGenerationTime());
+
+ timeStampToParameters.computeIfAbsent(
+ pvGenerationTime,
+ p -> {
+ return new HashMap();
+ });
+ String pvNameKey = pv.getId().getName();
+
+ for (String parameterName : this.parameters) {
+ var nameParts = parameterName.split("/");
+ var countedParams =
+ timeStampToParameters
+ .get(pvGenerationTime)
+ .computeIfAbsent(
+ nameParts[nameParts.length - 1],
+ p -> {
+ return new CountedParameterValue(null, 0);
+ });
+ }
+ timeStampToParameters.get(pvGenerationTime).put(pvNameKey, new CountedParameterValue(pv, 0));
+
+ jobBarrier.getAndAdd(1);
+ }
+}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportView.java b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportView.java
new file mode 100644
index 0000000000..8b504d6181
--- /dev/null
+++ b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ExportView.java
@@ -0,0 +1,533 @@
+/*******************************************************************************
+ * Copyright (c) 2010-2018 Oak Ridge National Laboratory.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package com.windhoverlabs.yamcs.applications.parameter;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.function.BiConsumer;
+import javafx.application.Platform;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.css.PseudoClass;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Button;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.RadioButton;
+import javafx.scene.control.TextField;
+import javafx.scene.control.TitledPane;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.control.Tooltip;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import org.csstudio.trends.databrowser3.Activator;
+import org.csstudio.trends.databrowser3.Messages;
+import org.csstudio.trends.databrowser3.export.Source;
+import org.csstudio.trends.databrowser3.model.Model;
+import org.csstudio.trends.databrowser3.ui.TimeRangePopover;
+import org.phoebus.archive.vtype.Style;
+import org.phoebus.framework.jobs.JobManager;
+import org.phoebus.framework.persistence.Memento;
+import org.phoebus.ui.dialog.DialogHelper;
+import org.phoebus.ui.dialog.ExceptionDetailsErrorDialog;
+import org.phoebus.ui.dialog.PopOver;
+import org.phoebus.ui.dialog.SaveAsDialog;
+import org.phoebus.ui.time.TimeRelativeIntervalPane;
+import org.phoebus.util.time.TimeRelativeInterval;
+
+/**
+ * Panel for exporting data into files
+ *
+ * @author Kay Kasemir
+ */
+@SuppressWarnings("nls")
+public class ExportView extends VBox {
+ private static final String TAG_SOURCE = "source",
+ TAG_OPTCOUNT = "optcount",
+ TAG_LININT = "linint",
+ TAG_TYPE = "type",
+ TAG_FORMAT = "format",
+ TAG_DIGITS = "digits",
+ TAG_FILE = "file";
+
+ private final TextField start = new TextField();
+
+ private final String utcRegex = "d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}+d{2}:d{2}";
+
+ public String getStart() {
+ return start.getText();
+ }
+
+ private final TextField end = new TextField();
+
+ public String getEnd() {
+ return end.getText();
+ }
+
+ void setEnd(String time) {
+ end.setText(time);
+ }
+
+ void setStart(String time) {
+ start.setText(time);
+ }
+
+ private final ToggleGroup sources = new ToggleGroup(),
+ table_types = new ToggleGroup(),
+ formats = new ToggleGroup();
+ private final TextField optimize = new TextField(Messages.ExportDefaultOptimization),
+ linear = new TextField(Messages.ExportDefaultLinearInterpolation),
+ format_digits = new TextField(Messages.ExportDefaultDigits),
+ filename = new TextField();
+ private final RadioButton source_raw = new RadioButton(Source.RAW_ARCHIVE.toString()),
+ type_matlab = new RadioButton(Messages.ExportTypeMatlab);
+
+ private final CheckBox useUnixTimeStamp = new CheckBox(Messages.UseUnixTimeStamp);
+ private SimpleBooleanProperty unixTimeStamp = new SimpleBooleanProperty(false);
+
+ private Model model = new org.csstudio.trends.databrowser3.model.Model();
+
+ // UnaryOperator numberValidationFormatter = change -> {
+ // if(change.getText().matches("\\d+")){
+ // return change; //if change is a number
+ // } else {
+ // change.setText(""); //else make no change
+ // change.setRange( //don't remove any selected text either.
+ // change.getRangeStart(),
+ // change.getRangeStart()
+ // );
+ // return change;
+ // }
+ // };
+
+ private ArrayList parameters = new ArrayList();
+
+ public ArrayList getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(ArrayList parameters) {
+ this.parameters = parameters;
+ }
+
+ /** @param model Model from which to export */
+ public ExportView() {
+ // * Samples To Export *
+ // Start: ___start_______________________________________________________________ [select]
+ // End : ___end_________________________________________________________________ [x] Use
+ // start/end time of Plot
+ // Source: ( ) Plot (*) Raw Archived Data ( ) Averaged Archived Data __time__ ( ) Linear
+ // __linear__
+
+ configureValidators();
+ GridPane grid = new GridPane();
+ grid.setHgap(5);
+ grid.setVgap(5);
+ grid.setPadding(new Insets(5));
+
+ grid.add(new Label(Messages.StartTimeLbl), 0, 0);
+ start.setPromptText("2023-08-20T04:30:44.424Z");
+ // start.va
+ // \\d{4}-[0-1]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\+\\d{4}
+ GridPane.setHgrow(start, Priority.ALWAYS);
+ grid.add(start, 1, 0);
+
+ final Button sel_times = new Button(Messages.StartEndDialogBtn);
+ sel_times.setTooltip(new Tooltip(Messages.StartEndDialogTT));
+ grid.add(sel_times, 2, 0);
+
+ grid.add(new Label(Messages.EndTimeLbl), 0, 1);
+ // end.setTooltip(new Tooltip(Messages.EndTimeTT));
+ end.setPromptText("2023-08-20T04:35:44.424Z");
+ GridPane.setHgrow(end, Priority.ALWAYS);
+ grid.add(end, 1, 1);
+
+ BiConsumer closeCallback =
+ (timePane, popOver) -> {
+ popOver.hide();
+ };
+ BiConsumer applyCallback =
+ (timePane, popOver) -> {
+ final String[] range = Model.getTimerangeText(timePane.getInterval());
+ start.setText(range[0]);
+ end.setText(range[1]);
+ popOver.hide();
+ };
+ final TimeRangePopover popover =
+ TimeRangePopover.withDefaultTimePane(model, closeCallback, applyCallback);
+ sel_times.setOnAction(
+ event -> {
+ popover.show((Region) event.getSource());
+ });
+
+ grid.add(new Label(Messages.ExportGroupSource), 0, 2);
+
+ // Order of source_* radio buttons must match the corresponding Source.* ordinal
+ final RadioButton source_plot = new RadioButton(Source.PLOT.toString());
+ source_plot.setTooltip(new Tooltip(Messages.ExportSource_PlotTT));
+ source_plot.setToggleGroup(sources);
+
+ source_raw.setTooltip(new Tooltip(Messages.ExportSource_RawArchiveTT));
+ source_raw.setToggleGroup(sources);
+
+ final RadioButton source_opt = new RadioButton(Source.OPTIMIZED_ARCHIVE.toString());
+ source_opt.setTooltip(new Tooltip(Messages.ExportSource_OptimizedArchiveTT));
+ source_opt.setToggleGroup(sources);
+
+ optimize.setPrefColumnCount(6);
+ optimize.setTooltip(new Tooltip(Messages.ExportOptimizationTT));
+ optimize.disableProperty().bind(source_opt.selectedProperty().not());
+
+ final RadioButton source_lin = new RadioButton(Source.LINEAR_INTERPOLATION.toString());
+ source_lin.setTooltip(new Tooltip(Messages.ExportSource_LinearTT));
+ source_lin.setToggleGroup(sources);
+
+ linear.setPrefColumnCount(8);
+ linear.setTooltip(new Tooltip(Messages.ExportDefaultLinearInterpolationTT));
+ linear.disableProperty().bind(source_lin.selectedProperty().not());
+
+ final HBox source_options =
+ new HBox(
+ 5, source_plot, source_raw, source_opt, optimize, source_lin, linear, useUnixTimeStamp);
+ source_options.setAlignment(Pos.CENTER_LEFT);
+ grid.add(source_options, 1, 2, 2, 1);
+
+ source_raw.setSelected(true);
+ source_options.setDisable(true);
+
+ final TitledPane source = new TitledPane(Messages.ExportGroupSource, grid);
+ source.setCollapsible(false);
+
+ // * Format *
+ // (*) Spreadsheet ( ) Matlab
+ // [x] Tabular [x] ... with min/max column [x] ... with Severity/Status
+ // (*) Default format ( ) decimal notation ( ) exponential notation _digits_ fractional digits
+ grid = new GridPane();
+ grid.setHgap(5);
+ grid.setVgap(5);
+ grid.setPadding(new Insets(5));
+
+ final RadioButton type_spreadsheet = new RadioButton(Messages.ExportTypeSpreadsheet);
+ type_spreadsheet.setTooltip(new Tooltip(Messages.ExportTypeSpreadsheetTT));
+ type_spreadsheet.setToggleGroup(table_types);
+ grid.add(type_spreadsheet, 0, 0);
+
+ type_matlab.setTooltip(new Tooltip(Messages.ExportTypeMatlabTT));
+ type_matlab.setToggleGroup(table_types);
+ grid.add(type_matlab, 1, 0);
+
+ type_spreadsheet.setSelected(true);
+
+ final RadioButton format_default = new RadioButton(Messages.Format_Default);
+ format_default.setTooltip(new Tooltip(Messages.ExportFormat_DefaultTT));
+ format_default.setToggleGroup(formats);
+ grid.add(format_default, 0, 2);
+
+ final RadioButton format_decimal = new RadioButton(Messages.Format_Decimal);
+ format_decimal.setTooltip(new Tooltip(Messages.ExportFormat_DecimalTT));
+ format_decimal.setToggleGroup(formats);
+ grid.add(format_decimal, 1, 2);
+
+ final RadioButton format_expo = new RadioButton(Messages.Format_Exponential);
+ format_expo.setTooltip(new Tooltip(Messages.ExportFormat_ExponentialTT));
+ format_expo.setToggleGroup(formats);
+ grid.add(format_expo, 2, 2);
+
+ format_digits.setPrefColumnCount(3);
+ format_digits.setTooltip(new Tooltip(Messages.ExportDigitsTT));
+ format_digits.disableProperty().bind(format_default.selectedProperty());
+ grid.add(format_digits, 3, 2);
+
+ // Formatting only applies to spreadsheet
+ format_default.disableProperty().bind(type_matlab.selectedProperty());
+ format_decimal.disableProperty().bind(type_matlab.selectedProperty());
+ format_expo.disableProperty().bind(type_matlab.selectedProperty());
+ format_digits.disableProperty().bind(type_matlab.selectedProperty());
+
+ grid.add(new Label(Messages.ExportDigits), 4, 2);
+
+ format_default.setSelected(true);
+
+ final TitledPane format = new TitledPane(Messages.ExportGroupFormat, grid);
+ format.setCollapsible(false);
+ format.setDisable(true);
+
+ // * Output *
+ // Filename: ______________ [Browse] [Export]
+ filename.setPromptText(Messages.ExportDefaultFilename);
+ filename.setTooltip(new Tooltip(Messages.ExportFilenameTT));
+
+ final Button sel_filename = new Button(Messages.ExportBrowse);
+ sel_filename.setTooltip(new Tooltip(Messages.ExportBrowseTT));
+ sel_filename.setOnAction(event -> selectFilename());
+
+ final Button export = new Button(Messages.ExportStartExport, Activator.getIcon("export"));
+ export.setOnAction(event -> startExportJob());
+
+ final HBox outputs =
+ new HBox(5, new Label(Messages.ExportFilename), filename, sel_filename, export);
+ outputs.setAlignment(Pos.CENTER_LEFT);
+ HBox.setHgrow(filename, Priority.ALWAYS);
+
+ final TitledPane output = new TitledPane(Messages.ExportGroupOutput, outputs);
+ output.setCollapsible(false);
+
+ getChildren().setAll(source, format, output);
+
+ // Enter in filename suggests to next start export
+ filename.setOnAction(event -> export.requestFocus());
+
+ useUnixTimeStamp.selectedProperty().bindBidirectional(unixTimeStamp);
+ }
+
+ void configureValidators() {
+ start
+ .textProperty()
+ .addListener(
+ event -> {
+ System.out.println("Changed:" + !start.getText().matches(utcRegex));
+ ;
+ start.pseudoClassStateChanged(
+ PseudoClass.getPseudoClass("error"),
+ !start.getText().isEmpty() && !start.getText().matches(utcRegex));
+ });
+ }
+
+ /** @return true
if the min/max (error) column option should be enabled */
+ private boolean minMaxAllowed() {
+ return !type_matlab.isSelected() && !source_raw.isSelected();
+ }
+
+ private void selectFilename() {
+ File file = new File(filename.getText().trim());
+ file = new SaveAsDialog().promptForFile(getScene().getWindow(), Messages.Export, file, null);
+ if (file != null) filename.setText(file.getAbsolutePath());
+ }
+
+ private void startExportJob() {
+ try {
+ // Determine start/end time
+ TimeRelativeInterval range = null;
+ // final Object s = TimeParser.parseInstantOrTemporalAmount(start.getText());
+ // final Object e = TimeParser.parseInstantOrTemporalAmount(end.getText());
+ // if (s instanceof Instant) {
+ // if (e instanceof Instant) range = TimeRelativeInterval.of((Instant) s, (Instant) e);
+ // else if (e instanceof TemporalAmount)
+ // range = TimeRelativeInterval.of((Instant) s, (TemporalAmount) e);
+ // } else if (s instanceof TemporalAmount) {
+ // if (e instanceof Instant) range = TimeRelativeInterval.of((TemporalAmount) s,
+ // (Instant) e);
+ // else if (e instanceof TemporalAmount)
+ // range = TimeRelativeInterval.of((TemporalAmount) s, (TemporalAmount) e);
+ // }
+ //
+ // if (range == null) throw new Exception("Invalid start..end time range");
+ //
+ // // Determine source: Plot, archive, ...
+ // final int src_index = sources.getToggles().indexOf(sources.getSelectedToggle());
+ // if (src_index < 0 || src_index >= Source.values().length)
+ // throw new Exception("Invalid sample source");
+ // final Source source = Source.values()[src_index];
+ // int optimize_parameter = -1;
+ // if (source == Source.OPTIMIZED_ARCHIVE) {
+ // try {
+ // optimize_parameter = Integer.parseInt(optimize.getText().trim());
+ // } catch (Exception ex) {
+ // ExceptionDetailsErrorDialog.openError(
+ // optimize,
+ // Messages.Error,
+ // Messages.ExportOptimizeCountError,
+ // new Exception(optimize.getText()));
+ // Platform.runLater(optimize::requestFocus);
+ // return;
+ // }
+ // } else if (source == Source.LINEAR_INTERPOLATION) {
+ // try {
+ // optimize_parameter = (int) (SecondsParser.parseSeconds(linear.getText().trim()) +
+ // 0.5);
+ // if (optimize_parameter < 1) optimize_parameter = 1;
+ // } catch (Exception ex) {
+ // ExceptionDetailsErrorDialog.openError(
+ // linear,
+ // Messages.Error,
+ // Messages.ExportLinearIntervalError,
+ // new Exception(linear.getText()));
+ // Platform.runLater(linear::requestFocus);
+ // return;
+ // }
+ // }
+
+ // Get remaining export parameters
+ final String filename = this.filename.getText().trim();
+ if (filename.isEmpty()) {
+ ExceptionDetailsErrorDialog.openError(
+ this.filename,
+ Messages.Error,
+ Messages.ExportEnterFilenameError,
+ new Exception(filename));
+ Platform.runLater(this.filename::requestFocus);
+ return;
+ }
+ if (new File(filename).exists()) {
+ final Alert dialog = new Alert(AlertType.CONFIRMATION);
+ dialog.setTitle(Messages.ExportFileExists);
+ dialog.setHeaderText(MessageFormat.format(Messages.ExportFileExistsFmt, filename));
+ DialogHelper.positionDialog(dialog, this.filename, -200, -200);
+ if (dialog.showAndWait().orElse(ButtonType.CANCEL) != ButtonType.OK) {
+ Platform.runLater(this.filename::requestFocus);
+ return;
+ }
+ }
+
+ // Construct appropriate export job
+ ExportCSVJob export;
+ // TimeInterval start_end = range.toAbsoluteInterval();
+ // if (type_matlab.isSelected()) { // Matlab file export
+ // if (filename.endsWith(".m"))
+ // export =
+ // new MatlabScriptExportJob(
+ // model,
+ // start_end.getStart(),
+ // start_end.getEnd(),
+ // source,
+ // optimize_parameter,
+ // filename,
+ // this::handleError,
+ // unixTimeStamp.get());
+ // else if (filename.endsWith(".mat"))
+ // export =
+ // new MatlabFileExportJob(
+ // model,
+ // start_end.getStart(),
+ // start_end.getEnd(),
+ // source,
+ // optimize_parameter,
+ // filename,
+ // this::handleError,
+ // unixTimeStamp.get());
+ // else {
+ // ExceptionDetailsErrorDialog.openError(
+ // this.filename,
+ // Messages.Error,
+ // Messages.ExportMatlabFilenameError,
+ // new Exception(filename));
+ // Platform.runLater(this.filename::requestFocus);
+ // return;
+ // }
+ // } else
+ { // Spreadsheet file export
+ Style style = Style.Default;
+
+ // Default, decimal, exponential
+ final int fmt = formats.getToggles().indexOf(formats.getSelectedToggle());
+ if (fmt == 1) style = Style.Decimal;
+ else if (fmt == 2) style = Style.Exponential;
+ int precision = 0;
+ if (style != Style.Default) {
+ try {
+ precision = Integer.parseInt(format_digits.getText().trim());
+ } catch (Exception ex) {
+ ExceptionDetailsErrorDialog.openError(
+ format_digits,
+ Messages.Error,
+ Messages.ExportDigitsError,
+ new Exception(format_digits.getText()));
+ Platform.runLater(format_digits::requestFocus);
+ return;
+ }
+ }
+ // ValueFormatter formatter = new ValueWithInfoFormatter(style,
+ // precision);
+
+ export =
+ new ExportCSVJob(
+ Instant.parse(start.getText()),
+ Instant.parse(end.getText()),
+ filename,
+ this::handleError,
+ unixTimeStamp.get(),
+ parameters);
+
+ // final ValueFormatter formatter;
+ // if (sev_stat.isSelected()) formatter = new ValueWithInfoFormatter(style,
+ // precision);
+ // else formatter = new ValueFormatter(style, precision);
+ // formatter.useMinMaxColumn(minMaxAllowed() && min_max_col.isSelected());
+ // if (tabular.isSelected())
+ // export =
+ // new SpreadsheetExportJob(
+ // model,
+ // start_end.getStart(),
+ // start_end.getEnd(),
+ // source,
+ // optimize_parameter,
+ // formatter,
+ // filename,
+ // this::handleError,
+ // unixTimeStamp.get());
+ // else
+ // export =
+ // new PlainExportJob(
+ // model,
+ // start_end.getStart(),
+ // start_end.getEnd(),
+ // source,
+ // optimize_parameter,
+ // formatter,
+ // filename,
+ // this::handleError,
+ // unixTimeStamp.get());
+ }
+
+ JobManager.schedule(filename, export);
+ } catch (Exception ex) {
+ handleError(ex);
+ }
+ }
+
+ private void handleError(final Exception ex) {
+ ExceptionDetailsErrorDialog.openError(this, Messages.Error, "Export error", ex);
+ }
+
+ /** @param memento Where to save current state */
+ public void save(final Memento memento) {
+ memento.setNumber(TAG_SOURCE, sources.getToggles().indexOf(sources.getSelectedToggle()));
+ memento.setString(TAG_OPTCOUNT, optimize.getText());
+ memento.setString(TAG_LININT, linear.getText());
+ memento.setNumber(TAG_TYPE, table_types.getToggles().indexOf(table_types.getSelectedToggle()));
+ memento.setNumber(TAG_FORMAT, formats.getToggles().indexOf(formats.getSelectedToggle()));
+ memento.setString(TAG_DIGITS, format_digits.getText());
+ memento.setString(TAG_FILE, filename.getText());
+ }
+
+ /** @param memento From where to restore saved state */
+ public void restore(final Memento memento) {
+ memento
+ .getNumber(TAG_SOURCE)
+ .ifPresent(index -> sources.selectToggle(sources.getToggles().get(index.intValue())));
+ memento.getString(TAG_OPTCOUNT).ifPresent(optimize::setText);
+ memento.getString(TAG_LININT).ifPresent(linear::setText);
+ memento
+ .getNumber(TAG_TYPE)
+ .ifPresent(
+ index -> table_types.selectToggle(table_types.getToggles().get(index.intValue())));
+ memento
+ .getNumber(TAG_FORMAT)
+ .ifPresent(index -> formats.selectToggle(formats.getToggles().get(index.intValue())));
+ memento.getString(TAG_DIGITS).ifPresent(format_digits::setText);
+ memento.getString(TAG_FILE).ifPresent(filename::setText);
+ }
+}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/Messages.java b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/Messages.java
new file mode 100644
index 0000000000..c9ec408a36
--- /dev/null
+++ b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/Messages.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oak Ridge National Laboratory.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ ******************************************************************************/
+package com.windhoverlabs.yamcs.applications.parameter;
+
+import org.phoebus.framework.nls.NLS;
+
+/**
+ * Eclipse string externalization
+ *
+ * @author Kay Kasemir
+ * @author Pavel Charvat
+ */
+public class Messages {
+ // ---
+ // --- Keep alphabetically sorted and 'in sync' with messages.properties!
+ // ---
+ public static String BaseDirectorySelTT;
+ public static String BaseDirectoryTT;
+ public static String BrowserRootTitle;
+ public static String ColName;
+ public static String ColSize;
+ public static String ColTime;
+ public static String CopyPathClp;
+ public static String CreateDirectoryErr;
+ public static String CreateDirectoryHdr;
+ public static String Delete;
+ public static String DeleteJobName;
+ public static String DeletePromptHeader;
+ public static String DeletePromptTitle;
+ public static String DisplayName;
+ public static String Duplicate;
+ public static String DuplicateAlert1;
+ public static String DuplicateAlert2;
+ public static String DuplicateJobName;
+ public static String DuplicatePrefix;
+ public static String DuplicatePromptHeader;
+ public static String HomeButtonTT;
+ public static String LookupJobName;
+ public static String MenuPath;
+ public static String MoveOrCopyAlert;
+ public static String MoveOrCopyAlertTitle;
+ public static String MoveOrCopyJobName;
+ public static String NewFolder;
+ public static String NewFolderAlert;
+ public static String Open;
+ public static String OpenAlert1;
+ public static String OpenAlert2;
+ public static String OpenWith;
+ public static String Paste;
+ public static String PropDlgBytes;
+ public static String PropDlgDate;
+ public static String PropDlgExecutable;
+ public static String PropDlgPath;
+ public static String PropDlgPermissions;
+ public static String PropDlgSize;
+ public static String PropDlgTitle;
+ public static String PropDlgWritable;
+ public static String Properties;
+ public static String Refresh;
+ public static String Rename;
+ public static String RenameHdr;
+ public static String RenameJobName;
+ public static String SetBaseDirectory;
+ // ---
+ // --- Keep alphabetically sorted and 'in sync' with messages.properties!
+ // ---
+
+ static {
+ NLS.initializeMessages(Messages.class);
+ }
+
+ private Messages() {
+ // Prevent instantiation
+ }
+}
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExport.java b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExport.java
similarity index 94%
rename from app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExport.java
rename to app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExport.java
index 2a38b2e64f..59450ed9c1 100644
--- a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/events/ParameterExport.java
+++ b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExport.java
@@ -1,6 +1,5 @@
-package com.windhoverlabs.yamcs.applications.events;
+package com.windhoverlabs.yamcs.applications.parameter;
-import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.phoebus.framework.preferences.AnnotatedPreferences;
@@ -22,7 +21,7 @@ public class ParameterExport implements AppDescriptor {
static {
AnnotatedPreferences.initialize(ParameterExport.class, "/eventviewer_preferences.properties");
}
-
+
@Override
public String getName() {
return Name;
diff --git a/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExportController.java b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExportController.java
new file mode 100644
index 0000000000..1986f1d867
--- /dev/null
+++ b/app/commander/app-commander-parameter-export/src/main/java/com/windhoverlabs/yamcs/applications/parameter/ParameterExportController.java
@@ -0,0 +1,235 @@
+package com.windhoverlabs.yamcs.applications.parameter;
+
+import com.windhoverlabs.pv.yamcs.YamcsAware;
+import com.windhoverlabs.yamcs.core.CMDR_Event;
+import com.windhoverlabs.yamcs.core.YamcsObjectManager;
+import com.windhoverlabs.yamcs.core.YamcsServer;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.beans.Observable;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.geometry.Orientation;
+import javafx.scene.Node;
+import javafx.scene.control.SplitPane;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.control.cell.CheckBoxTableCell;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.input.KeyCode;
+import javafx.scene.layout.GridPane;
+import javafx.util.Callback;
+import org.csstudio.trends.databrowser3.Activator;
+import org.csstudio.trends.databrowser3.Messages;
+import org.phoebus.framework.autocomplete.PVProposalService;
+import org.phoebus.framework.autocomplete.Proposal;
+import org.phoebus.framework.autocomplete.ProposalService;
+
+public class ParameterExportController {
+ class ExportPV {
+ private final SimpleBooleanProperty export = new SimpleBooleanProperty();
+ private final SimpleStringProperty pv = new SimpleStringProperty();
+
+ ExportPV(String pv, boolean export) {
+ this.pv.set(pv);
+ this.export.set(export);
+ }
+
+ public final SimpleStringProperty pvProperty() {
+ return pv;
+ }
+
+ public final SimpleBooleanProperty exportProperty() {
+ return export;
+ }
+ }
+
+ public static final Logger log =
+ Logger.getLogger(ParameterExportController.class.getPackageName());
+
+ private final TableView tableView = new TableView();
+
+ TableColumn exportColumn = new TableColumn("export");
+ TableColumn pvColumn = new TableColumn("pv");
+
+ private ObservableList data =
+ FXCollections.observableArrayList(new ArrayList());
+ private static final int dataSize = 10_023;
+
+ private ProposalService proposalService = PVProposalService.INSTANCE;
+
+ // TODO:Eventually these will be in spinner nodes. These are the event filters.
+ private String currentServer = "sitl";
+ private String currentInstance = "yamcs-cfs";
+
+ YamcsAware yamcsListener = null;
+
+ @FXML private GridPane gridPane;
+
+ @FXML private TextField pvTextField;
+
+ private ObservableList proposalList = FXCollections.observableArrayList();
+ private HashSet exportSet = new HashSet();
+
+ private ExportView paramExportView = new ExportView();
+
+ public ExportView getParamExportView() {
+ return paramExportView;
+ }
+
+ private Tab exportTab;
+ @FXML private TabPane exportTabPane;
+ @FXML private SplitPane mainSplit;
+
+ public Node getRootPane() {
+ return mainSplit;
+ }
+
+ @FXML
+ public void initialize() {
+ tableView.setId("paramExportTable");
+
+ pvColumn.setCellValueFactory(new PropertyValueFactory<>("pv"));
+ pvColumn.setCellValueFactory(cellData -> cellData.getValue().pvProperty());
+
+ exportColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.3));
+ pvColumn.prefWidthProperty().bind(tableView.widthProperty().multiply(0.7));
+ exportColumn.minWidthProperty().bind(tableView.widthProperty().multiply(0.3));
+ pvColumn.minWidthProperty().bind(tableView.widthProperty().multiply(0.7));
+ exportColumn.setCellValueFactory(cellData -> cellData.getValue().exportProperty());
+ exportColumn.setCellFactory(tc -> new CheckBoxTableCell<>());
+
+ this.proposalList =
+ FXCollections.observableArrayList(
+ new Callback() {
+
+ @Override
+ public Observable[] call(ExportPV param) {
+ return new Observable[] {param.exportProperty()};
+ }
+ });
+
+ this.proposalList.addListener(
+ new ListChangeListener() {
+
+ @Override
+ public void onChanged(ListChangeListener.Change extends ExportPV> c) {
+ while (c.next()) {
+ if (c.wasUpdated()) {
+ ExportPV item = proposalList.get(c.getFrom());
+ if (item.exportProperty().get()) {
+ exportSet.add(item.pvProperty().get());
+ } else {
+ exportSet.remove(item.pvProperty().get());
+ }
+ paramExportView.getParameters().clear();
+ exportSet.forEach(
+ p -> {
+ paramExportView.getParameters().add(p);
+ });
+ }
+ }
+ }
+ });
+ // tableView.setColumnResizePolicy(null);
+ tableView.getColumns().addAll(pvColumn, exportColumn);
+
+ yamcsListener =
+ new YamcsAware() {
+ public void changeDefaultInstance() {
+ tableView.refresh();
+ }
+
+ public void onYamcsConnected() {
+ if (YamcsObjectManager.getDefaultInstance() != null) {
+ YamcsObjectManager.getDefaultInstance()
+ .getEvents()
+ .addListener(
+ new ListChangeListener
+
+ com.windhoverlabs
+ app-commander-parameter-export
+ 0.2.6-SNAPSHOT
+
com.windhoverlabs
app-commander-connections
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-events
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
+
+
+ com.windhoverlabs
+ app-commander-links
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-command-options
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
commander-core
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-display-model
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-display-representation-javafx
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
com.windhoverlabs
app-commander-display-runtime
- 0.2.4-SNAPSHOT
+ 0.2.6-SNAPSHOT
org.phoebus
diff --git a/pom.xml b/pom.xml
index 0f1b87b0af..7f92c8de3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -126,6 +126,7 @@
public
+ false
@@ -375,7 +376,7 @@
none
-
+ false