From 02250d94287ff94247598be52d11242bf77d39ac Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 5 Dec 2024 01:52:16 +0100 Subject: [PATCH 01/10] Upgrade Maven plugin version to 3.6.3 for git-commit-id-maven-plugin:9.0.1 compatibility see https://jitpack.io/com/github/ControlSystemStudio/phoebus/-v4.7.3-g9c0f55d-959/build.log --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0834e2e0c..df41a171cb 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,8 @@ maven-jar-plugin - 3.3.0 + + 3.6.3 From f7416b2fa1ee4b5f0f9e495a7b866df690451392 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 5 Dec 2024 02:01:59 +0100 Subject: [PATCH 02/10] Revert "Upgrade Maven plugin version to 3.6.3 for git-commit-id-maven-plugin:9.0.1 compatibility see https://jitpack.io/com/github/ControlSystemStudio/phoebus/-v4.7.3-g9c0f55d-959/build.log" This reverts commit 02250d94287ff94247598be52d11242bf77d39ac. --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df41a171cb..e0834e2e0c 100644 --- a/pom.xml +++ b/pom.xml @@ -163,8 +163,7 @@ maven-jar-plugin - - 3.6.3 + 3.3.0 From 9721669a0f35aeeb7b7e2d66395196486e7c03c6 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 5 Dec 2024 02:32:11 +0100 Subject: [PATCH 03/10] Update Maven version for git-commit compatibility --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e0834e2e0c..4102f3f312 100644 --- a/pom.xml +++ b/pom.xml @@ -99,7 +99,7 @@ maven-compiler-plugin - 3.6.2 + 3.9.0 17 17 From 279cbf020317aaaf92dbff624d3f2036b2f0934d Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 5 Dec 2024 02:45:13 +0100 Subject: [PATCH 04/10] Comment git-commit-id-maven-plugin for jitpack --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4102f3f312..c633e4ad31 100644 --- a/pom.xml +++ b/pom.xml @@ -166,6 +166,8 @@ 3.3.0 + + From 7317c472c890019d8ec659db8b5715461d60e546 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 9 Jan 2025 14:18:48 +0100 Subject: [PATCH 05/10] Fix bug for Variable that contains dot in the name and add a tooltip on description cell --- .../pvtable/model/PVTableItem.java | 32 +++++++++++++++---- .../applications/pvtable/ui/PVTable.java | 21 ++++++++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java index b93f472ba0..c6a8e9e6de 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java @@ -52,6 +52,7 @@ public class PVTableItem /** Value of the PV's description */ private volatile String desc_value = ""; + private volatile String desc_name = ""; /** Saved (snapshot) value */ private volatile Optional saved = Optional.empty(); @@ -77,6 +78,9 @@ public class PVTableItem /** Listener to description PV */ private volatile Disposable desc_flow; + + private static final String DESC_FIELD = "DESC"; + private static final String DOT = "."; /** Initialize * @@ -148,12 +152,23 @@ private void createPVs(final String name) name.startsWith("loc:"))) { // Determine DESC field. - // If name already includes a field, - // replace it with DESC field. - final int sep = name.lastIndexOf('.'); - final String desc_name = sep >= 0 - ? name.substring(0, sep) + ".DESC" - : name + ".DESC"; + //Bug when a pv name contains a . caracters + desc_name = name + DOT + DESC_FIELD; + if(!name.endsWith(DOT + DESC_FIELD) && name.contains(DOT)) { + // If name already includes a field + // It can be a EPICS fields such as .VAL .EGU ... + // EPICS fields are always in Upper Case + // EPICS fields are 4 characters length max + final int sep = name.lastIndexOf('.'); + String fieldVal = name.substring(sep + 1); + //System.out.println("fieldVal=" + fieldVal); + //Test if it in uppercase and max length 4 + boolean isEpicsField = fieldVal.toUpperCase().equals(fieldVal) && fieldVal.length() < 5; + if(isEpicsField) { + desc_name = name.replace(fieldVal, DESC_FIELD); + } + } + try { final PV new_desc_pv = PVPool.getPV(desc_name); @@ -244,6 +259,11 @@ public String getDescription() { return desc_value; } + + /** @return description pv name **/ + public String getDescriptionName() { + return desc_name; + } /** @return Enum options for current value, null if not enumerated */ public String[] getValueOptions() diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java index 9bbfef2466..7699b736db 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java @@ -83,8 +83,6 @@ import javafx.scene.paint.Color; import javafx.util.converter.DefaultStringConverter; -import static org.phoebus.ui.application.PhoebusApplication.logger; - /** PV Table and its toolbar * @author Kay Kasemir @@ -164,6 +162,24 @@ protected void updateItem(final Boolean selected, final boolean empty) } } } + + private static class DescriptionTableCell extends TableCell + { + @Override + protected void updateItem(final String item, final boolean empty) + { + super.updateItem(item, empty); + setText(item); + final int row = getIndex(); + final List items = getTableView().getItems(); + if (! empty && row >= 0 && row < items.size()) { + final TableItemProxy itemCell = items.get(row); + if(itemCell != null && itemCell.getItem() != null) { + setTooltip(new Tooltip(itemCell.getItem().getDescriptionName())); + } + } + } + } /** Table cell for 'name' column, colors comments */ private static class PVNameTableCell extends TextFieldTableCell @@ -784,6 +800,7 @@ private void createTableColumns() { col = new TableColumn<>(Messages.Description); col.setCellValueFactory(cell -> cell.getValue().desc_value); + col.setCellFactory(column -> new DescriptionTableCell()); table.getColumns().add(col); } From 1e0b79c1f13ac2e1f41eaecb79a379e7d78963c5 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 9 Jan 2025 14:30:49 +0100 Subject: [PATCH 06/10] Rebase on last master version --- pom.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 84eee9e1c7..d5659b26f0 100644 --- a/pom.xml +++ b/pom.xml @@ -99,7 +99,7 @@ maven-compiler-plugin - 3.9.0 + 3.6.2 17 17 @@ -166,8 +166,6 @@ 3.3.0 - - + From 0a7c78a252bb9bf68117e024178e4e466f45254e Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 9 Jan 2025 15:26:44 +0100 Subject: [PATCH 07/10] Set maven version for jitpack build https://jitpack.io/com/github/ControlSystemStudio/phoebus/ --- jitpack.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 jitpack.yml diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000000..6f11682178 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,20 @@ +name: Phoebus build + +on: + push: + branches-ignore: + - 'master' + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Maven and Java Action + uses: s4u/setup-maven-action@v1.13.0 + with: + java-version: '17' + maven-version: '3.9.6' + - name: Build + run: mvn --batch-mode install -DskipTests \ No newline at end of file From 85ce31245273e2422f49f5274efe5f8cb4581600 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Thu, 9 Jan 2025 16:34:11 +0100 Subject: [PATCH 08/10] Specify maven version for jitpack --- jitpack.yml | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/jitpack.yml b/jitpack.yml index 6f11682178..f2c3aeef88 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,20 +1,5 @@ -name: Phoebus build - -on: - push: - branches-ignore: - - 'master' - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup Maven and Java Action - uses: s4u/setup-maven-action@v1.13.0 - with: - java-version: '17' - maven-version: '3.9.6' - - name: Build - run: mvn --batch-mode install -DskipTests \ No newline at end of file +before_install: + # update maven version 3.9.9 + - sdk install maven 3.9.9 +install: + - mvn install -DskipTests \ No newline at end of file From 2df512af6a9a084641eff536c71b0521cde1add9 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Fri, 10 Jan 2025 20:19:55 +0100 Subject: [PATCH 09/10] Get the description from VType first or PV using DisplayProvider interface, add a list of PV in the PVTable using TextArea --- .../pvtable/model/PVTableItem.java | 88 ++++++++++++------- .../applications/pvtable/ui/Messages.java | 1 + .../applications/pvtable/ui/PVTable.java | 39 ++++++-- .../pvtable/ui/messages.properties | 1 + .../pvtable/ui/messages_fr.properties | 1 + 5 files changed, 92 insertions(+), 38 deletions(-) diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java index c6a8e9e6de..213376134d 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java @@ -18,6 +18,8 @@ import org.epics.vtype.Alarm; import org.epics.vtype.AlarmSeverity; import org.epics.vtype.AlarmStatus; +import org.epics.vtype.Display; +import org.epics.vtype.DisplayProvider; import org.epics.vtype.Time; import org.epics.vtype.VByteArray; import org.epics.vtype.VEnum; @@ -30,6 +32,7 @@ import org.phoebus.core.vtypes.VTypeHelper; import org.phoebus.pv.PV; import org.phoebus.pv.PVPool; +import org.phoebus.pv.PVPool.TypedName; import io.reactivex.rxjava3.disposables.Disposable; @@ -51,7 +54,7 @@ public class PVTableItem private volatile VType value; /** Value of the PV's description */ - private volatile String desc_value = ""; + private volatile String desc_value = null; private volatile String desc_name = ""; /** Saved (snapshot) value */ @@ -126,16 +129,24 @@ private void createPVs(final String name) updateValue(null); return; } + PV new_pv = null; try { updateValue(VString.of("", Alarm.disconnected(), Time.now())); - final PV new_pv = PVPool.getPV(name); + new_pv = PVPool.getPV(name); value_flow = new_pv.onValueEvent() .throttleLatest(Settings.max_update_period_ms, TimeUnit.MILLISECONDS) .subscribe(this::updateValue); permission_flow = new_pv.onAccessRightsEvent() .subscribe(writable -> listener.tableItemChanged(PVTableItem.this)); pv.set(new_pv); + // read the value for getting description + if (new_pv != null) { + VType newVal = new_pv.read(); + if(newVal != null){ + updateValue(newVal); + } + } } catch (Exception ex) { @@ -145,28 +156,23 @@ private void createPVs(final String name) Time.now())); } - // For CA PVs, check the .DESC field - // Hardcoded knowledge to avoid non-record PVs. - if (Settings.show_description && - ! (name.startsWith("sim:") || - name.startsWith("loc:"))) - { - // Determine DESC field. - //Bug when a pv name contains a . caracters - desc_name = name + DOT + DESC_FIELD; - if(!name.endsWith(DOT + DESC_FIELD) && name.contains(DOT)) { - // If name already includes a field - // It can be a EPICS fields such as .VAL .EGU ... - // EPICS fields are always in Upper Case - // EPICS fields are 4 characters length max + // First try to get description from value or pv + updateDescription(); + // If still no description found and channel access source + final TypedName type_name = TypedName.analyze(name); + String dataType = type_name != null ? type_name.type : null; + boolean channelAccess = dataType.equals("ca"); + if (Settings.show_description && desc_value == null && channelAccess) { + // For CA PVs, check the .DESC field + // Hardcoded knowledge to avoid non-record PVs. + // First get default datasource + desc_name = name + DOT + DESC_FIELD; // by default add .DESC + if (!name.endsWith(DOT + DESC_FIELD) && name.contains(DOT)) { final int sep = name.lastIndexOf('.'); String fieldVal = name.substring(sep + 1); - //System.out.println("fieldVal=" + fieldVal); - //Test if it in uppercase and max length 4 - boolean isEpicsField = fieldVal.toUpperCase().equals(fieldVal) && fieldVal.length() < 5; - if(isEpicsField) { - desc_name = name.replace(fieldVal, DESC_FIELD); - } + // then replace by .DESC + // Determine DESC field include dot in case of variable name such as variableEGUName + desc_name = name.replace(DOT + fieldVal, DOT + DESC_FIELD); } try @@ -190,6 +196,24 @@ private void createPVs(final String name) } } } + + private void updateDescription() { + if(desc_value == null) { + //update description from value or pv + VType currentValue = getValue(); + if(currentValue != null) { + PV thePV = pv.get(); + Display display = thePV instanceof DisplayProvider ? ((DisplayProvider) thePV).getDisplay() : null; + display = display == null && currentValue instanceof DisplayProvider ? ((DisplayProvider) currentValue).getDisplay(): display; + if (display != null) { + String description = display.getDescription(); + desc_value = description != null ? description : null; + desc_name = desc_value != null ? "Description of " + name + " PV" : "no description"; + desc_flow = value_flow; + } + } + } + } /** @return true if item is selected to be restored */ public boolean isSelected() @@ -255,9 +279,8 @@ public VType getValue() } /** @return Description */ - public String getDescription() - { - return desc_value; + public String getDescription() { + return desc_value == null ? "" : desc_value; } /** @return description pv name **/ @@ -305,14 +328,17 @@ public void setValue(String new_value) throw new Exception("Not connected"); final VType pv_type = the_pv.read(); - if (pv_type instanceof VNumber) - { - if (Settings.show_units) - { // Strip units so that only the number gets written - final String units = ((VNumber)pv_type).getDisplay().getUnit(); - if (units.length() > 0 && new_value.endsWith(units)) + Display display = the_pv instanceof DisplayProvider ? ((DisplayProvider) the_pv).getDisplay() : null; + display = display == null && pv_type instanceof DisplayProvider ? ((DisplayProvider) pv_type).getDisplay():null; + + if (display != null && Settings.show_units) { + // Strip units so that only the number gets written + final String units = display.getUnit(); + if (units.length() > 0 && new_value.endsWith(units)) new_value = new_value.substring(0, new_value.length() - units.length()).trim(); } + if (pv_type instanceof VNumber) + { the_pv.write(Double.parseDouble(new_value)); } else if (pv_type instanceof VEnum) diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/Messages.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/Messages.java index 493c06469e..527faafafa 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/Messages.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/Messages.java @@ -14,6 +14,7 @@ public class Messages { /** Externalized strings */ public static String Alarm, + AddPVList, Description, CheckAll, CheckAll_TT, diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java index 7699b736db..f2d2103800 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/ui/PVTable.java @@ -69,7 +69,9 @@ import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TableView.TableViewSelectionModel; +import javafx.scene.control.TextArea; import javafx.scene.control.TextField; +import javafx.scene.control.TextInputControl; import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; import javafx.scene.control.cell.TextFieldTableCell; @@ -93,6 +95,7 @@ public class PVTable extends VBox private static final String comment_style = "-fx-text-fill: blue;"; private static final String new_item_style = "-fx-text-fill: gray;"; private static final String changed_style = "-fx-background-color: -fx-table-cell-border-color, cyan;-fx-background-insets: 0, 0 0 1 0;"; + private static final String SPLIT_PV = "[ \\t\\n\\r,]+"; /** When sorting, keep the 'NEW_ITEM' row at the bottom **/ private static final Comparator SORT_NEW_ITEM_LAST = (a, b) -> @@ -184,8 +187,9 @@ protected void updateItem(final String item, final boolean empty) /** Table cell for 'name' column, colors comments */ private static class PVNameTableCell extends TextFieldTableCell { - private TextField textField; - + private TextInputControl textField; + private static ContextMenu contextMenu; + public PVNameTableCell() { super(new DefaultStringConverter()); @@ -195,11 +199,26 @@ public PVNameTableCell() public void startEdit() { super.startEdit(); - textField = new TextField(); - textField.setOnAction(event -> commitEdit(textField.getText())); + final int index = getIndex(); + boolean newPv = index == getTableView().getItems().size() - 1; + if(newPv) { + textField = new TextArea(); + textField.setMaxHeight(100); + if(contextMenu == null) { + MenuItem addPVMenu = new MenuItem(Messages.AddPVList); + addPVMenu.setOnAction(event -> commitEdit(textField.getText())); + contextMenu = new ContextMenu(addPVMenu); + } + textField.setContextMenu(contextMenu); + } + else { + textField = new TextField(); + ((TextField)textField).setOnAction(event -> commitEdit(textField.getText())); + } PVAutocompleteMenu.INSTANCE.attachField(textField); showCurrentValue(); } + private void showCurrentValue() { @@ -775,8 +794,14 @@ private void createTableColumns() final TableItemProxy proxy = event.getRowValue(); if (proxy == TableItemProxy.NEW_ITEM) { - if (!new_name.isEmpty()) - model.addItem(new_name); + if (!new_name.isEmpty()) { + //Can be a list of pv + final String[] pvs = new_name.split(SPLIT_PV); + //Add a list + for(String pv : pvs) { + model.addItem(pv); + } + } // else: No name entered, do nothing } else @@ -976,7 +1001,7 @@ else if (db.hasString()) private void addPVsFromString(final PVTableItem existing, final String pv_text) { - final String[] pvs = pv_text.split("[ \\t\\n\\r,]+"); + final String[] pvs = pv_text.split(SPLIT_PV); for (String pv : pvs) if (! pv.isEmpty()) model.addItemAbove(existing, pv); diff --git a/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages.properties b/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages.properties index 43e0e1dde9..ab62a29720 100644 --- a/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages.properties +++ b/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages.properties @@ -1,4 +1,5 @@ Alarm=Alarm +AddPVList=Add a list of pv Description=Description CheckAll=Check All CheckAll_TT=Check all PVs in table diff --git a/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages_fr.properties b/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages_fr.properties index 64a1976d73..7b069fb941 100644 --- a/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages_fr.properties +++ b/app/pvtable/src/main/resources/org/phoebus/applications/pvtable/ui/messages_fr.properties @@ -1,4 +1,5 @@ Alarm=Alarme +AddPVList=Ajout d une liste de pv Description=Description CheckAll=Tout sélectionner CheckAll_TT=Sélectionner tous les PVs dans le tableau From c3ab02a1234d0f6c8d64c635bb83519b3387e473 Mon Sep 17 00:00:00 2001 From: ksaintin Date: Tue, 14 Jan 2025 19:05:28 +0100 Subject: [PATCH 10/10] Add comment to explain why check if PV instanceof DisplayProvider see pullrequest #3228 --- .../org/phoebus/applications/pvtable/model/PVTableItem.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java index 213376134d..6e902bb4b9 100644 --- a/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java +++ b/app/pvtable/src/main/java/org/phoebus/applications/pvtable/model/PVTableItem.java @@ -203,6 +203,9 @@ private void updateDescription() { VType currentValue = getValue(); if(currentValue != null) { PV thePV = pv.get(); + // DisplayProvider is an optional interface for VType values, + // not PVs, but the custum datasource as Muscade happens to implement + // DisplayProvider for enum and bool PVs, so check for that here Display display = thePV instanceof DisplayProvider ? ((DisplayProvider) thePV).getDisplay() : null; display = display == null && currentValue instanceof DisplayProvider ? ((DisplayProvider) currentValue).getDisplay(): display; if (display != null) {