From 1d23e536b93fc01504c87c895fdbdfbb14a60e8b Mon Sep 17 00:00:00 2001 From: georgweiss Date: Thu, 7 Nov 2024 16:51:26 +0100 Subject: [PATCH 1/8] backup of WIP for Olog templates --- .../org/phoebus/olog/es/api/OlogClient.java | 34 +++++++++++++++++++ .../olog/ui/AttachmentsViewController.java | 2 +- .../ui/write/AttachmentsEditorController.java | 6 +++- .../logbook/olog/ui/messages.properties | 4 +++ .../java/org/phoebus/logbook/LogClient.java | 16 +++++++++ .../java/org/phoebus/logbook/LogTemplate.java | 20 +++++++++++ 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java diff --git a/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogClient.java b/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogClient.java index 81abb57115..a127982ca6 100644 --- a/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogClient.java +++ b/app/logbook/olog/client-es/src/main/java/org/phoebus/olog/es/api/OlogClient.java @@ -20,6 +20,7 @@ import org.phoebus.logbook.LogClient; import org.phoebus.logbook.LogEntry; import org.phoebus.logbook.LogEntryChangeHandler; +import org.phoebus.logbook.LogTemplate; import org.phoebus.logbook.Logbook; import org.phoebus.logbook.LogbookException; import org.phoebus.logbook.Messages; @@ -43,6 +44,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.http.HttpHeaders; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -562,4 +564,36 @@ public SearchResult getArchivedEntries(long id){ throw new RuntimeException(e); } } + + @Override + public Collection getTemplates(){ + try { + return OlogObjectMappers.logEntryDeserializer.readValue( + service.path("templates").accept(MediaType.APPLICATION_JSON).get(String.class), + new TypeReference>() { + }); + } catch (UniformInterfaceException | ClientHandlerException | IOException e) { + logger.log(Level.WARNING, "Unable to get templates from service", e); + return Collections.emptySet(); + } + } + + @Override + public LogTemplate saveTemplate(LogTemplate template) throws LogbookException{ + ClientResponse clientResponse = service.path("templates").accept(MediaType.APPLICATION_JSON_TYPE) + .header("Content-Type", MediaType.APPLICATION_JSON_TYPE) + .put(ClientResponse.class, template); + if (clientResponse.getStatus() > 300) { + logger.log(Level.SEVERE, "Failed to create template: " + clientResponse); + throw new LogbookException(clientResponse.toString()); + } + + try { + return OlogObjectMappers.logEntryDeserializer.readValue(clientResponse.getEntityInputStream(), LogTemplate.class); + } catch (IOException e) { + logger.log(Level.SEVERE, "Failed to submit template, got client exception", e); + throw new LogbookException(e); + } + + } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/AttachmentsViewController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/AttachmentsViewController.java index 5a791d621e..8d291b27c9 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/AttachmentsViewController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/AttachmentsViewController.java @@ -321,7 +321,7 @@ public void removeAttachments(List attachmentsToRemove) { attachments.removeAll(attachmentsToRemove); } - public List getAttachments() { + public ObservableList getAttachments() { return attachments; } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java index 471eb626f9..3115e218f0 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java @@ -23,6 +23,8 @@ import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.embed.swing.SwingFXUtils; import javafx.fxml.FXML; import javafx.scene.control.Alert; @@ -75,6 +77,8 @@ public class AttachmentsEditorController { private final Logger logger = Logger.getLogger(AttachmentsEditorController.class.getName()); private final SimpleBooleanProperty imageAttachmentSelected = new SimpleBooleanProperty(false); + private final ObservableList attachmentList = FXCollections.observableArrayList(); + /** * List of (temporary) attachment {@link File}s deleted when log entry has been successfully persisted. @@ -320,7 +324,7 @@ private void addImage(Image image, String id) { } } - public List getAttachments() { + public ObservableList getAttachments() { return attachmentsViewController.getAttachments(); } diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties index 574928e692..e8920d51e1 100644 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties +++ b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties @@ -32,6 +32,7 @@ Date=Date: DownloadSelected=Download Selected DownloadingAttachments=Downloading Attachments EditLogEntry=Edit Log Entry +EditNewTemplate=Edit New Template EmbedImage=Embed New EmbedImageTooltip=Embed image from file or clipboard in log entry body EmbedSelected=Embed Selected @@ -81,6 +82,7 @@ Remove_Tooltip=Remove the selected items. RequestTooLarge=Total file size exceeds limit, selected file(s) not added. Reply=Reply ReplyToLogEntry=Reply To Log Entry +SaveAsTemplate=Save as template ScalingFactor=Scaling Factor SearchButtonText=Search: Search=Search available: @@ -91,6 +93,7 @@ SelectFolder=Select Folder SelectFile=Select Image File SelectLevelTooltip=Select the log entry level. SelectLogEntry=Select Log Entry +SelectTemplate=Select Template ServiceConnectionError=Unable to connect to the logbook service ShowHelp=Show Help ShowHideDetails=Show/Hide Details @@ -104,6 +107,7 @@ SubmitTooltip=Submit Log Entry Tags=Tags: TagsTitle=Select Tags TagsTooltip=Add tag to the log entry. +Templates=Templates: Text=Text: Time=Time: Title=Title: diff --git a/core/logbook/src/main/java/org/phoebus/logbook/LogClient.java b/core/logbook/src/main/java/org/phoebus/logbook/LogClient.java index d3945dd6c9..1fb91d8be3 100644 --- a/core/logbook/src/main/java/org/phoebus/logbook/LogClient.java +++ b/core/logbook/src/main/java/org/phoebus/logbook/LogClient.java @@ -513,4 +513,20 @@ default String serviceInfo(){ default SearchResult getArchivedEntries(long id){ return null; } + + /** + * @return All potentially empty {@link Collection} of {@link LogTemplate} saved in remote service. + */ + default Collection getTemplates(){ + return Collections.emptyList(); + } + + /** + * Saves a new {@link LogTemplate} + * @param logTemplate Data + * @return The persisted {@link LogTemplate} + */ + default LogTemplate saveTemplate(LogTemplate logTemplate) throws LogbookException{ + return null; + } } diff --git a/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java new file mode 100644 index 0000000000..1b33611d78 --- /dev/null +++ b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2024 European Spallation Source ERIC. + */ + +package org.phoebus.logbook; + +import java.time.Instant; +import java.util.Collection; + +public record LogTemplate(String id, + String name, + String owner, + Instant createdDate, + Instant modifiedDate, + String title, + String source, + Collection logbooks, + Collection tags, + Collection properties){ +} From 4870334df6a18f1902772d2a550d43f0f0ae2148 Mon Sep 17 00:00:00 2001 From: georgweiss Date: Fri, 8 Nov 2024 15:30:55 +0100 Subject: [PATCH 2/8] Loading log templates --- .../ui/write/LogEntryEditorController.java | 114 ++++++++++++++++-- .../write/LogPropertiesEditorController.java | 7 ++ .../logbook/olog/ui/messages.properties | 1 - .../logbook/olog/ui/write/LogEntryEditor.fxml | 12 +- .../java/org/phoebus/logbook/LogTemplate.java | 5 + 5 files changed, 128 insertions(+), 11 deletions(-) diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java index 365537a9d1..622c04b818 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java @@ -31,14 +31,38 @@ import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.geometry.Side; -import javafx.scene.control.*; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.CustomMenuItem; +import javafx.scene.control.Label; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.MenuItem; +import javafx.scene.control.PasswordField; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.util.Callback; +import javafx.util.StringConverter; import org.phoebus.framework.jobs.JobManager; import org.phoebus.framework.selection.SelectionService; -import org.phoebus.logbook.*; +import org.phoebus.logbook.LogClient; +import org.phoebus.logbook.LogEntry; +import org.phoebus.logbook.LogFactory; +import org.phoebus.logbook.LogService; +import org.phoebus.logbook.LogTemplate; +import org.phoebus.logbook.Logbook; +import org.phoebus.logbook.LogbookException; +import org.phoebus.logbook.LogbookPreferences; +import org.phoebus.logbook.Tag; import org.phoebus.logbook.olog.ui.HelpViewer; import org.phoebus.logbook.olog.ui.LogbookUIPreferences; import org.phoebus.logbook.olog.ui.PreviewViewer; @@ -55,7 +79,11 @@ import org.phoebus.util.time.TimestampFormats; import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -97,12 +125,12 @@ public class LogEntryEditorController { @FXML private TextField userField; @FXML + private TextField dateField; + @FXML private PasswordField passwordField; @FXML private Label levelLabel; @FXML - private TextField dateField; - @FXML private ComboBox levelSelector; @FXML private Label titleLabel; @@ -124,6 +152,10 @@ public class LogEntryEditorController { private TextField logbooksSelection; @FXML private TextField tagsSelection; + @FXML + private HBox templateControls; + @FXML + private ComboBox templateSelector; private final ContextMenu logbookDropDown = new ContextMenu(); private final ContextMenu tagDropDown = new ContextMenu(); @@ -199,6 +231,8 @@ public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, LogEntryC @FXML public void initialize() { + templateControls.managedProperty().bind(templateControls.visibleProperty()); + // This could be configured in the fxml, but then these UI components would not be visible // in Scene Builder. completionMessageLabel.textProperty().set(""); @@ -211,6 +245,7 @@ public void initialize() { return; } + submitButton.managedProperty().bind(submitButton.visibleProperty()); submitButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !inputValid.get() || submissionInProgress.get(), inputValid, submissionInProgress)); @@ -272,9 +307,9 @@ public void initialize() { selectedLevelProperty.set(logEntry.getLevel() != null ? logEntry.getLevel() : availableLevels.get(0)); levelSelector.getSelectionModel().select(selectedLevelProperty.get()); - dateField.setText(TimestampFormats.DATE_FORMAT.format(Instant.now())); + titleField.textProperty().bindBidirectional(titleProperty); titleProperty.addListener((changeListener, oldVal, newVal) -> { @@ -368,15 +403,71 @@ public void initialize() { ); selectedTags.addListener((ListChangeListener) change -> { + if(change.getList() == null){ + return; + } List newSelection = new ArrayList<>(change.getList()); tagsPopOver.setAvailable(availableTagsAsStringList, newSelection); tagsPopOver.setSelected(newSelection); + newSelection.forEach(t -> updateDropDown(tagDropDown, t, true)); }); selectedLogbooks.addListener((ListChangeListener) change -> { + if(change.getList() == null){ + return; + } List newSelection = new ArrayList<>(change.getList()); logbooksPopOver.setAvailable(availableLogbooksAsStringList, newSelection); logbooksPopOver.setSelected(newSelection); + newSelection.forEach(l -> updateDropDown(logbookDropDown, l, true)); + }); + + templateSelector.setCellFactory(new Callback<>() { + @Override + public ListCell call(ListView logTemplateListView) { + return new ListCell<>() { + @Override + protected void updateItem(LogTemplate item, boolean empty) { + super.updateItem(item, empty); + if (item == null || empty) { + setGraphic(null); + } else { + setGraphic(new Label(item.name())); + } + } + }; + } + }); + + templateSelector.valueProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + if (!newValue.equals(oldValue)) { + loadTemplate(newValue); + } + } + }); + + templateSelector.setConverter( + new StringConverter<>() { + @Override + public String toString(LogTemplate template) { + if (template == null) { + return ""; + } else { + return template.name(); + } + } + + @Override + public LogTemplate fromString(String s) { + return null; + } + }); + + JobManager.schedule("Get templates", monitor -> { + LogClient logClient = logFactory.getLogClient(); + Collection templates = logClient.getTemplates(); + Platform.runLater(() -> templateSelector.getItems().addAll(templates)); }); // Note: logbooks and tags are retrieved asynchronously from service @@ -701,8 +792,17 @@ private boolean checkConnectivity() { logClient.serviceInfo(); return true; } catch (Exception e) { - Logger.getLogger(SendToLogBookApp.class.getName()).warning("Failed to query logbook service, it may be off-line."); + Logger.getLogger(LogEntryEditorController.class.getName()).warning("Failed to query logbook service, it may be off-line."); return false; } } + + private void loadTemplate(LogTemplate logTemplate){ + titleProperty.set(logTemplate.title()); + descriptionProperty.set(logTemplate.source()); + logPropertiesEditorController.setProperties(logTemplate.properties()); + selectedTags.setAll(logTemplate.tags().stream().map(Tag::getName).toList()); + selectedLogbooks.setAll(logTemplate.logbooks().stream().map(Logbook::getName).toList()); + levelSelector.getSelectionModel().select(logTemplate.level()); + } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java index f59ba0e764..2be0256bbd 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java @@ -173,6 +173,13 @@ public List getProperties() { return selectedProperties; } + public void setProperties(Collection properties){ + if(properties == null){ + return; + } + selectedProperties.addAll(properties); + } + /** * Move the user selected available properties from the available list to the selected properties tree view */ diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties index e8920d51e1..b42849624f 100644 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties +++ b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/messages.properties @@ -32,7 +32,6 @@ Date=Date: DownloadSelected=Download Selected DownloadingAttachments=Downloading Attachments EditLogEntry=Edit Log Entry -EditNewTemplate=Edit New Template EmbedImage=Embed New EmbedImageTooltip=Embed image from file or clipboard in log entry body EmbedSelected=Embed Selected diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml index b9a9803de1..454eca8309 100644 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml +++ b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml @@ -23,7 +23,7 @@ - + @@ -45,6 +45,13 @@ + + + + @@ -219,8 +226,7 @@ - diff --git a/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java index 1b33611d78..fe288017b5 100644 --- a/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java +++ b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java @@ -14,7 +14,12 @@ public record LogTemplate(String id, Instant modifiedDate, String title, String source, + String level, Collection logbooks, Collection tags, Collection properties){ + + public LogTemplate(){ + this(null, null, null, null, null, null, null, null, null, null, null); + } } From 47b495b1a82c99fbe2a7a131961446e45fd2a944 Mon Sep 17 00:00:00 2001 From: georgweiss Date: Wed, 20 Nov 2024 15:02:05 +0100 Subject: [PATCH 3/8] Backup commit --- .../ui/write/LogEntryEditorController.java | 63 ++++++++++++++----- .../write/LogPropertiesEditorController.java | 1 + .../logbook/olog/ui/write/LogEntryEditor.fxml | 4 +- .../java/org/phoebus/logbook/LogTemplate.java | 18 ++++-- 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java index 622c04b818..9ba81c5bdf 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java @@ -66,7 +66,6 @@ import org.phoebus.logbook.olog.ui.HelpViewer; import org.phoebus.logbook.olog.ui.LogbookUIPreferences; import org.phoebus.logbook.olog.ui.PreviewViewer; -import org.phoebus.logbook.olog.ui.menu.SendToLogBookApp; import org.phoebus.olog.es.api.OlogProperties; import org.phoebus.olog.es.api.model.OlogLog; import org.phoebus.security.store.SecureStore; @@ -99,16 +98,22 @@ public class LogEntryEditorController { private final Logger logger = Logger.getLogger(LogEntryEditorController.class.getName()); @FXML + @SuppressWarnings("unused") private VBox editorPane; @FXML + @SuppressWarnings("unused") private VBox errorPane; @FXML + @SuppressWarnings("unused") private Button submitButton; @FXML + @SuppressWarnings("unused") private Button cancelButton; @FXML + @SuppressWarnings("unused") private ProgressIndicator progressIndicator; @FXML + @SuppressWarnings("unused") private Label completionMessageLabel; @SuppressWarnings("unused") @@ -119,42 +124,61 @@ public class LogEntryEditorController { private LogPropertiesEditorController logPropertiesEditorController; @FXML + @SuppressWarnings("unused") private Label userFieldLabel; @FXML + @SuppressWarnings("unused") private Label passwordFieldLabel; @FXML + @SuppressWarnings("unused") private TextField userField; @FXML + @SuppressWarnings("unused") private TextField dateField; @FXML + @SuppressWarnings("unused") private PasswordField passwordField; @FXML + @SuppressWarnings("unused") private Label levelLabel; @FXML + @SuppressWarnings("unused") private ComboBox levelSelector; @FXML + @SuppressWarnings("unused") private Label titleLabel; @FXML + @SuppressWarnings("unused") private TextField titleField; @FXML + @SuppressWarnings("unused") private TextArea textArea; @FXML + @SuppressWarnings("unused") private Button addLogbooks; @FXML + @SuppressWarnings("unused") private Button addTags; @FXML + @SuppressWarnings("unused") private ToggleButton logbooksDropdownButton; @FXML + @SuppressWarnings("unused") private ToggleButton tagsDropdownButton; @FXML + @SuppressWarnings("unused") private Label logbooksLabel; @FXML + @SuppressWarnings("unused") private TextField logbooksSelection; @FXML + @SuppressWarnings("unused") private TextField tagsSelection; @FXML + @SuppressWarnings("unused") private HBox templateControls; @FXML + @SuppressWarnings("unused") private ComboBox templateSelector; private final ContextMenu logbookDropDown = new ContextMenu(); @@ -202,10 +226,6 @@ public class LogEntryEditorController { */ private String originalTitle = ""; - /** - * Version of remote service - */ - private String serverVersion; public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, LogEntryCompletionHandler logEntryCompletionHandler) { this.replyTo = inReplyTo; @@ -313,12 +333,12 @@ public void initialize() { titleField.textProperty().bindBidirectional(titleProperty); titleProperty.addListener((changeListener, oldVal, newVal) -> { - if (newVal.trim().isEmpty()) { + if (newVal == null || newVal.trim().isEmpty()) { titleLabel.setTextFill(Color.RED); } else { titleLabel.setTextFill(Color.BLACK); } - if (!newVal.equals(originalTitle)) { + if (newVal != null && !newVal.equals(originalTitle)) { isDirty = true; } }); @@ -403,7 +423,7 @@ public void initialize() { ); selectedTags.addListener((ListChangeListener) change -> { - if(change.getList() == null){ + if (change.getList() == null) { return; } List newSelection = new ArrayList<>(change.getList()); @@ -413,7 +433,7 @@ public void initialize() { }); selectedLogbooks.addListener((ListChangeListener) change -> { - if(change.getList() == null){ + if (change.getList() == null) { return; } List newSelection = new ArrayList<>(change.getList()); @@ -487,6 +507,7 @@ public void cancel() { } @FXML + @SuppressWarnings("unused") public void showHelp() { new HelpViewer(LogbookUIPreferences.markup_help).show(); } @@ -495,12 +516,14 @@ public void showHelp() { * Handler for HTML preview button */ @FXML + @SuppressWarnings("unused") public void showHtmlPreview() { new PreviewViewer(getDescription(), attachmentsEditorController.getAttachments()).show(); } @FXML + @SuppressWarnings("unused") public void submit() { submissionInProgress.set(true); @@ -563,6 +586,7 @@ public void submit() { } @FXML + @SuppressWarnings("unused") public void setLevel() { selectedLevelProperty.set(levelSelector.getSelectionModel().getSelectedItem()); } @@ -576,6 +600,7 @@ public String getDescription() { } @FXML + @SuppressWarnings("unused") public void addLogbooks() { logbooksPopOver.show(addLogbooks); } @@ -597,15 +622,16 @@ private void setSelectedLogbooks(List proposedLogbooks, List exi private void setSelected(List proposed, List existing, Consumer addFunction, Consumer removeFunction) { List addedTags = proposed.stream() .filter(tag -> !existing.contains(tag)) - .collect(Collectors.toList()); + .toList(); List removedTags = existing.stream() .filter(tag -> !proposed.contains(tag)) - .collect(Collectors.toList()); + .toList(); addedTags.forEach(addFunction); removedTags.forEach(removeFunction); } @FXML + @SuppressWarnings("unused") public void selectLogbooks() { if (logbooksDropdownButton.isSelected()) { logbookDropDown.show(logbooksSelection, Side.BOTTOM, 0, 0); @@ -615,6 +641,7 @@ public void selectLogbooks() { } @FXML + @SuppressWarnings("unused") public void addTags() { tagsPopOver.show(addTags); } @@ -634,6 +661,7 @@ private void setSelectedTags(List proposedTags, List existingTag } @FXML + @SuppressWarnings("unused") public void selectTags() { if (tagsDropdownButton.isSelected()) { tagDropDown.show(tagsSelection, Side.BOTTOM, 0, 0); @@ -666,7 +694,7 @@ private void getServerSideStaticData() { Collections.sort(availableLogbooksAsStringList); List preSelectedLogbooks = - logEntry.getLogbooks().stream().map(Logbook::getName).collect(Collectors.toList()); + logEntry.getLogbooks().stream().map(Logbook::getName).toList(); List defaultLogbooks = Arrays.asList(LogbookUIPreferences.default_logbooks); availableLogbooksAsStringList.forEach(logbook -> { CheckBox checkBox = new CheckBox(logbook); @@ -697,7 +725,7 @@ private void getServerSideStaticData() { Collections.sort(availableLogbooksAsStringList); List preSelectedTags = - logEntry.getTags().stream().map(Tag::getName).collect(Collectors.toList()); + logEntry.getTags().stream().map(Tag::getName).toList(); availableTagsAsStringList.forEach(tag -> { CheckBox checkBox = new CheckBox(tag); CustomMenuItem newTag = new CustomMenuItem(checkBox); @@ -727,7 +755,6 @@ private void getServerSideStaticData() { ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(serverInfo); - serverVersion = jsonNode.get("version").asText(); attachmentsEditorController.setSizeLimits(jsonNode.get("serverConfig").get("maxFileSize").asText(), jsonNode.get("serverConfig").get("maxRequestSize").asText()); } catch (Exception e) { @@ -797,12 +824,18 @@ private boolean checkConnectivity() { } } - private void loadTemplate(LogTemplate logTemplate){ + /** + * Loads template to configure UI elements. + * @param logTemplate A {@link LogTemplate} selected by user. + */ + private void loadTemplate(LogTemplate logTemplate) { titleProperty.set(logTemplate.title()); descriptionProperty.set(logTemplate.source()); logPropertiesEditorController.setProperties(logTemplate.properties()); selectedTags.setAll(logTemplate.tags().stream().map(Tag::getName).toList()); selectedLogbooks.setAll(logTemplate.logbooks().stream().map(Logbook::getName).toList()); levelSelector.getSelectionModel().select(logTemplate.level()); + selectedTags.forEach(t -> updateDropDown(tagDropDown, t, true)); + selectedLogbooks.forEach(l -> updateDropDown(logbookDropDown, l, true)); } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java index 2be0256bbd..463cbae732 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogPropertiesEditorController.java @@ -178,6 +178,7 @@ public void setProperties(Collection properties){ return; } selectedProperties.addAll(properties); + availableProperties.removeAll(properties); } /** diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml index 454eca8309..f78a1c688c 100644 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml +++ b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml @@ -49,8 +49,8 @@ diff --git a/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java index fe288017b5..9d7c41fa43 100644 --- a/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java +++ b/core/logbook/src/main/java/org/phoebus/logbook/LogTemplate.java @@ -7,6 +7,20 @@ import java.time.Instant; import java.util.Collection; +/** + * Encapsulates elements representing a log entry template. + * @param id Unique id, determined and set by service when a {@link LogTemplate} is created, i.e. may be null + * @param name A case-insensitive name for the {@link LogTemplate}, must be unique among all saved {@link LogTemplate}s. + * @param owner User id set by service when a {@link LogTemplate} is created, i.e. may be null + * @param createdDate Create date set by service when a {@link LogTemplate} is created, i.e. may be null + * @param modifiedDate Modify date set by service when a {@link LogTemplate} is created, i.e. may be null + * @param title May be null. + * @param source Markdown body content. May be null. + * @param level Must not be null or empty. + * @param logbooks May be null or empty list. + * @param tags May be null or empty list. + * @param properties May be null or empty list. + */ public record LogTemplate(String id, String name, String owner, @@ -18,8 +32,4 @@ public record LogTemplate(String id, Collection logbooks, Collection tags, Collection properties){ - - public LogTemplate(){ - this(null, null, null, null, null, null, null, null, null, null, null); - } } From 5b042bb1bdac1837b934b19d05001f9469c6be02 Mon Sep 17 00:00:00 2001 From: georgweiss Date: Fri, 22 Nov 2024 13:54:05 +0100 Subject: [PATCH 4/8] Removed LogEntryCompletionHandler, added EditMode --- .../olog/ui/LogEntryDisplayController.java | 5 +- .../olog/ui/LogEntryTableViewController.java | 11 ++-- .../ui/write/AttachmentsEditorController.java | 25 +++++---- .../olog/ui/write/ContextMenuLogging.java | 2 +- .../logbook/olog/ui/write/EditMode.java | 11 ++++ .../ui/write/LogEntryCompletionHandler.java | 27 ---------- .../ui/write/LogEntryEditorController.java | 51 ++++++++++++------- .../olog/ui/write/LogEntryEditorStage.java | 30 ++++++++--- .../ui/write/LogEntryUpdateController.java | 8 +-- .../olog/ui/write/LogEntryUpdateStage.java | 19 +++---- .../logbook/olog/ui/write/LogEntryEditor.fxml | 2 +- .../logbook/ui/menu/SendLogbookAction.java | 2 +- .../logbook/ui/menu/SendToLogBookApp.java | 2 +- .../logbook/ui/write/ContextMenuLogging.java | 2 +- .../ui/write/LogEntryCompletionHandler.java | 27 ---------- .../ui/write/LogEntryEditorController.java | 18 ++++--- .../logbook/ui/write/LogEntryEditorStage.java | 28 +++++++--- .../ui/write/LogEntryEditorStageDemo.java | 2 +- .../csstudio/display/pace/PACEInstance.java | 50 +++++++++--------- 19 files changed, 161 insertions(+), 161 deletions(-) create mode 100644 app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/EditMode.java delete mode 100644 app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryCompletionHandler.java delete mode 100644 app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryCompletionHandler.java diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryDisplayController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryDisplayController.java index 92b7fa8d54..751a79a001 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryDisplayController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryDisplayController.java @@ -35,6 +35,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import org.phoebus.logbook.LogEntry; +import org.phoebus.logbook.olog.ui.write.EditMode; import org.phoebus.logbook.olog.ui.write.LogEntryEditorStage; import org.phoebus.olog.es.api.model.LogGroupProperty; import org.phoebus.olog.es.api.model.OlogLog; @@ -137,13 +138,13 @@ public void showHideLogEntryGroup() { public void reply() { // Show a new editor dialog. When user selects to save the reply entry, update the original log entry // to ensure that it contains the log group property. - new LogEntryEditorStage(new OlogLog(), logEntryProperty.get(), null).show(); + new LogEntryEditorStage(new OlogLog(), logEntryProperty.get(), EditMode.NEW_LOG_ENTRY).show(); } @FXML public void newLogEntry(){ // Show a new editor dialog. - new LogEntryEditorStage(new OlogLog(), null, null).show(); + new LogEntryEditorStage(new OlogLog(), null, EditMode.NEW_LOG_ENTRY).show(); } @FXML diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java index 0bd4769216..1d82b573ce 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java @@ -48,8 +48,9 @@ import org.phoebus.logbook.SearchResult; import org.phoebus.logbook.olog.ui.query.OlogQuery; import org.phoebus.logbook.olog.ui.query.OlogQueryManager; +import org.phoebus.logbook.olog.ui.write.EditMode; import org.phoebus.logbook.olog.ui.write.LogEntryEditorStage; -import org.phoebus.logbook.olog.ui.write.LogEntryUpdateStage; +//import org.phoebus.logbook.olog.ui.write.LogEntryUpdateStage; import org.phoebus.olog.es.api.model.LogGroupProperty; import org.phoebus.olog.es.api.model.OlogLog; import org.phoebus.security.store.SecureStore; @@ -185,12 +186,16 @@ public void initialize() { MenuItem menuItemNewLogEntry = new MenuItem(Messages.NewLogEntry); menuItemNewLogEntry.acceleratorProperty().setValue(new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN)); - menuItemNewLogEntry.setOnAction(ae -> new LogEntryEditorStage(new OlogLog(), null, null).show()); + menuItemNewLogEntry.setOnAction(ae -> { + new LogEntryEditorStage(new OlogLog(), null, EditMode.NEW_LOG_ENTRY).showAndWait(); + }); MenuItem menuItemUpdateLogEntry = new MenuItem(Messages.UpdateLogEntry); menuItemUpdateLogEntry.visibleProperty().bind(Bindings.createBooleanBinding(() -> selectedLogEntries.size() == 1, selectedLogEntries)); menuItemUpdateLogEntry.acceleratorProperty().setValue(new KeyCodeCombination(KeyCode.U, KeyCombination.CONTROL_DOWN)); - menuItemUpdateLogEntry.setOnAction(ae -> new LogEntryUpdateStage(selectedLogEntries.get(0), null).show()); + menuItemUpdateLogEntry.setOnAction(ae -> { + new LogEntryEditorStage(selectedLogEntries.get(0), null, EditMode.UPDATE_LOG_ENTRY).show(); + }); contextMenu.getItems().addAll(groupSelectedEntries, menuItemShowHideAll, menuItemNewLogEntry); if (LogbookUIPreferences.log_entry_update_support) { diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java index d5629cf9ac..9a7c4f8958 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/AttachmentsEditorController.java @@ -84,8 +84,6 @@ public class AttachmentsEditorController { private final Logger logger = Logger.getLogger(AttachmentsEditorController.class.getName()); private final SimpleBooleanProperty imageAttachmentSelected = new SimpleBooleanProperty(false); - private final ObservableList attachmentList = FXCollections.observableArrayList(); - /** * List of (temporary) attachment {@link File}s deleted when log entry has been successfully persisted. @@ -121,26 +119,31 @@ public class AttachmentsEditorController { private final SimpleStringProperty sizeLimitsText = new SimpleStringProperty(); /** - * @param logEntry The log entry template potentially holding a set of attachments. Note + * @param logEntry The log entry potentially holding a set of attachments. Note * that files associated with these attachments are considered temporary and * are subject to removal when the log entry has been committed. */ public AttachmentsEditorController(LogEntry logEntry) { this.logEntry = logEntry; - // If the log entry has an attachment - e.g. log entry created from display or data browser - - // then add the file size to the total attachments size - Collection attachments = logEntry.getAttachments(); - if (attachments != null && !attachments.isEmpty()) { - attachments.forEach(a -> attachedFilesSize += getFileSize(a.getFile())); - } } @FXML public void initialize() { - attachmentsViewController.setAttachments(logEntry.getAttachments()); + // If the log entry has an attachment - e.g. log entry created from display or data browser - + // then add the file size to the total attachments size. + Collection attachments = logEntry.getAttachments(); + if (attachments != null && !attachments.isEmpty()) { + attachments.forEach(a -> { + if(a.getFile() != null){ + attachedFilesSize += getFileSize(a.getFile()); + } + }); + } + + attachmentsViewController.setAttachments(attachments); - filesToDeleteAfterSubmit.addAll(logEntry.getAttachments().stream().map(Attachment::getFile).toList()); + filesToDeleteAfterSubmit.addAll(attachments.stream().map(Attachment::getFile).toList()); removeButton.setGraphic(ImageCache.getImageView(ImageCache.class, "/icons/delete.png")); removeButton.disableProperty().bind(Bindings.isEmpty(attachmentsViewController.getSelectedAttachments())); diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/ContextMenuLogging.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/ContextMenuLogging.java index 8907ca28e1..0086e44e8b 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/ContextMenuLogging.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/ContextMenuLogging.java @@ -44,7 +44,7 @@ public void call(Node parent, Selection selection) { adaptedSelections.add(adapted); }); }); - new LogEntryEditorStage(adaptedSelections.get(0), null, null).show(); + new LogEntryEditorStage(adaptedSelections.get(0), null, EditMode.NEW_LOG_ENTRY).show(); } @Override diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/EditMode.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/EditMode.java new file mode 100644 index 0000000000..aac9c57b90 --- /dev/null +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/EditMode.java @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2024 European Spallation Source ERIC. + */ + +package org.phoebus.logbook.olog.ui.write; + +public enum EditMode { + + NEW_LOG_ENTRY, + UPDATE_LOG_ENTRY +} diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryCompletionHandler.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryCompletionHandler.java deleted file mode 100644 index 897ab97ff1..0000000000 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryCompletionHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2019 European Spallation Source ERIC. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -package org.phoebus.logbook.olog.ui.write; - -import org.phoebus.logbook.LogEntry; - -public interface LogEntryCompletionHandler { - - public void handleResult(LogEntry logEntry); -} diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java index 9ba81c5bdf..df35ea52ad 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java @@ -31,6 +31,7 @@ import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.geometry.Side; +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; @@ -83,6 +84,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -93,8 +95,6 @@ */ public class LogEntryEditorController { - private final LogEntryCompletionHandler completionHandler; - private final Logger logger = Logger.getLogger(LogEntryEditorController.class.getName()); @FXML @@ -181,6 +181,10 @@ public class LogEntryEditorController { @SuppressWarnings("unused") private ComboBox templateSelector; + @FXML + @SuppressWarnings("unused") + private Node attachmentsPane; + private final ContextMenu logbookDropDown = new ContextMenu(); private final ContextMenu tagDropDown = new ContextMenu(); @@ -226,11 +230,15 @@ public class LogEntryEditorController { */ private String originalTitle = ""; + private EditMode editMode; - public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, LogEntryCompletionHandler logEntryCompletionHandler) { + private Optional logEntryResult = Optional.empty(); + + + public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, EditMode editMode) { this.replyTo = inReplyTo; - this.completionHandler = logEntryCompletionHandler; this.logFactory = LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory); + this.editMode = editMode; updateCredentialsProperty = updateCredentials; // This is the reply case: @@ -251,13 +259,6 @@ public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, LogEntryC @FXML public void initialize() { - templateControls.managedProperty().bind(templateControls.visibleProperty()); - - // This could be configured in the fxml, but then these UI components would not be visible - // in Scene Builder. - completionMessageLabel.textProperty().set(""); - progressIndicator.visibleProperty().bind(submissionInProgress); - // Remote log service not reachable, so show error pane. if (!checkConnectivity()) { errorPane.visibleProperty().set(true); @@ -265,6 +266,17 @@ public void initialize() { return; } + templateControls.managedProperty().bind(templateControls.visibleProperty()); + templateControls.visibleProperty().setValue(editMode.equals(EditMode.NEW_LOG_ENTRY)); + + attachmentsPane.managedProperty().bind(attachmentsPane.visibleProperty()); + attachmentsPane.visibleProperty().setValue(editMode.equals(EditMode.NEW_LOG_ENTRY)); + + // This could be configured in the fxml, but then these UI components would not be visible + // in Scene Builder. + completionMessageLabel.textProperty().set(""); + progressIndicator.visibleProperty().bind(submissionInProgress); + submitButton.managedProperty().bind(submitButton.visibleProperty()); submitButton.disableProperty().bind(Bindings.createBooleanBinding(() -> !inputValid.get() || submissionInProgress.get(), @@ -540,19 +552,15 @@ public void submit() { LogClient logClient = logFactory.getLogClient(new SimpleAuthenticationToken(usernameProperty.get(), passwordProperty.get())); - LogEntry result; try { if (replyTo == null) { - result = logClient.set(ologLog); + logEntryResult = Optional.of(logClient.set(ologLog)); } else { - result = logClient.reply(ologLog, replyTo); + logEntryResult = Optional.of(logClient.reply(ologLog, replyTo)); } - // Not dirty any more... + // Not dirty anymore... isDirty = false; - if (result != null) { - if (completionHandler != null) { - completionHandler.handleResult(result); - } + if (logEntryResult.isPresent()) { // Set username and password in secure store if submission of log entry completes successfully if (Preferences.save_credentials) { // Get the SecureStore. Store username and password. @@ -824,8 +832,13 @@ private boolean checkConnectivity() { } } + public Optional getLogEntryResult(){ + return logEntryResult; + } + /** * Loads template to configure UI elements. + * * @param logTemplate A {@link LogTemplate} selected by user. */ private void loadTemplate(LogTemplate logTemplate) { diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java index 2911280d1b..97c0d57b9b 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java @@ -35,29 +35,36 @@ import org.phoebus.ui.dialog.DialogHelper; import java.util.Collection; +import java.util.Optional; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; +/** + * {@link Stage} subclass rendering a UI for the purpose of editing/submitting a {@link LogEntry}. + * Callers that need to handle the outcome (i.e. when the {@link Stage} is closed) should + * call first call {@link #showAndWait()} and then get a potential result using {@link #getLogEntryResult()}. + */ public class LogEntryEditorStage extends Stage { private LogEntryEditorController logEntryEditorController; /** * A stand-alone window containing components needed to create a logbook entry. * - * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screen shot. + * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screenshot. */ public LogEntryEditorStage(LogEntry logEntry) { - this(logEntry, null, null); + this(logEntry, null, EditMode.NEW_LOG_ENTRY); } /** * A stand-alone window containing components needed to create a logbook entry. * - * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screen shot. - * @param completionHandler A completion handler called when service call completes. + * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screenshot. + * @param replyTo Existing {@link LogEntry} for which the new {@link LogEntry} is a reply. If null, + * then it is assumed this is invoked to not crate a reply. */ - public LogEntryEditorStage(LogEntry logEntry, LogEntry replyTo, LogEntryCompletionHandler completionHandler) { + public LogEntryEditorStage(LogEntry logEntry, LogEntry replyTo, EditMode editMode) { initModality(Modality.WINDOW_MODAL); ResourceBundle resourceBundle = NLS.getMessages(Messages.class); @@ -66,8 +73,8 @@ public LogEntryEditorStage(LogEntry logEntry, LogEntry replyTo, LogEntryCompleti fxmlLoader.setControllerFactory(clazz -> { try { if (clazz.isAssignableFrom(LogEntryEditorController.class)) { - logEntryEditorController = (LogEntryEditorController) clazz.getConstructor(LogEntry.class, LogEntry.class, LogEntryCompletionHandler.class) - .newInstance(logEntry, replyTo, completionHandler); + logEntryEditorController = (LogEntryEditorController) clazz.getConstructor(LogEntry.class, LogEntry.class, EditMode.class) + .newInstance(logEntry, replyTo, editMode); return logEntryEditorController; } else if (clazz.isAssignableFrom(AttachmentsEditorController.class)) { return clazz.getConstructor(LogEntry.class).newInstance(logEntry); @@ -126,4 +133,13 @@ public void handleCloseEditor(boolean entryIsDirty, Node parent) { close(); } } + + /** + * + * @return A potentially empty result of {@link LogEntry} submission. + */ + @SuppressWarnings("unused") + public Optional getLogEntryResult(){ + return logEntryEditorController.getLogEntryResult(); + } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java index dfb9c0727a..5300ad614d 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java @@ -67,8 +67,6 @@ */ public class LogEntryUpdateController { - private final LogEntryCompletionHandler completionHandler; - private final Logger logger = Logger.getLogger(LogEntryUpdateController.class.getName()); @FXML @@ -172,9 +170,8 @@ public class LogEntryUpdateController { private String originalTitle = ""; - public LogEntryUpdateController(LogEntry logEntry, LogEntryCompletionHandler logEntryCompletionHandler) { + public LogEntryUpdateController(LogEntry logEntry) { this.logId = logEntry.getId(); - this.completionHandler = logEntryCompletionHandler; this.logFactory = LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory); updateCredentialsProperty = updateCredentials; this.logEntry = logEntry; @@ -425,9 +422,6 @@ public void submit() { // Not dirty any more... isDirty = false; if (result != null) { - if (completionHandler != null) { - completionHandler.handleResult(result); - } // Set username and password in secure store if submission of log entry completes successfully if (Preferences.save_credentials) { // Get the SecureStore. Store username and password. diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java index 229da95c04..dab81fa79c 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java @@ -39,25 +39,18 @@ import java.util.logging.Level; import java.util.logging.Logger; +/** + * + */ public class LogEntryUpdateStage extends Stage { private LogEntryUpdateController logEntryUpdateController; - - /** - * A stand-alone window containing components needed to create a logbook entry. - * - * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screen shot. - */ - public LogEntryUpdateStage(LogEntry logEntry) { - this(logEntry, null); - } - /** * A stand-alone window containing components needed to create a logbook entry. * * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screen shot. * @param completionHandler A completion handler called when service call completes. */ - public LogEntryUpdateStage(LogEntry logEntry, LogEntryCompletionHandler completionHandler) { + public LogEntryUpdateStage(LogEntry logEntry) { initModality(Modality.WINDOW_MODAL); ResourceBundle resourceBundle = NLS.getMessages(Messages.class); @@ -65,8 +58,8 @@ public LogEntryUpdateStage(LogEntry logEntry, LogEntryCompletionHandler completi fxmlLoader.setControllerFactory(clazz -> { try { if (clazz.isAssignableFrom(LogEntryUpdateController.class)) { - logEntryUpdateController = (LogEntryUpdateController) clazz.getConstructor(LogEntry.class, LogEntryCompletionHandler.class) - .newInstance(logEntry, completionHandler); + logEntryUpdateController = (LogEntryUpdateController) clazz.getConstructor(LogEntry.class) + .newInstance(logEntry); return logEntryUpdateController; } else if (clazz.isAssignableFrom(AttachmentsEditorController.class)) { return clazz.getConstructor(LogEntry.class).newInstance(logEntry); diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml index f78a1c688c..6fb8337f15 100644 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml +++ b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryEditor.fxml @@ -163,7 +163,7 @@ - + diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendLogbookAction.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendLogbookAction.java index d5b217f891..1e225a84c6 100644 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendLogbookAction.java +++ b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendLogbookAction.java @@ -108,7 +108,7 @@ private void submitLogEntry(final Node parent, final String title, final String final LogEntryModel model = new LogEntryModel(logEntryBuilder.createdDate(Instant.now()).build()); - new LogEntryEditorStage(parent, model, null).show(); + new LogEntryEditorStage(parent, model).show(); } } diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendToLogBookApp.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendToLogBookApp.java index 894dfa2ef4..ac0b86eea2 100644 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendToLogBookApp.java +++ b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/menu/SendToLogBookApp.java @@ -44,7 +44,7 @@ public AppInstance create() if(!LogbookAvailabilityChecker.isLogbookAvailable()){ return null; } - new LogEntryEditorStage(DockPane.getActiveDockPane(), new LogEntryModel(), null).show(); + new LogEntryEditorStage(DockPane.getActiveDockPane(), new LogEntryModel()).show(); return null; } diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/ContextMenuLogging.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/ContextMenuLogging.java index 407336d1ca..ddcb97940a 100644 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/ContextMenuLogging.java +++ b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/ContextMenuLogging.java @@ -45,7 +45,7 @@ public void call(Node parent, Selection selection) { }); }); final LogEntryModel model = new LogEntryModel(adaptedSelections.get(0)); - new LogEntryEditorStage(parent, model, null).show(); + new LogEntryEditorStage(parent, model).show(); } @Override diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryCompletionHandler.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryCompletionHandler.java deleted file mode 100644 index 89ff6fd0d0..0000000000 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryCompletionHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2019 European Spallation Source ERIC. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -package org.phoebus.logbook.ui.write; - -import org.phoebus.logbook.LogEntry; - -public interface LogEntryCompletionHandler { - - public void handleResult(LogEntry logEntry); -} diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorController.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorController.java index 6079d3ce63..8d47319138 100644 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorController.java +++ b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorController.java @@ -31,6 +31,7 @@ import org.phoebus.logbook.LogEntry; import org.phoebus.logbook.ui.Messages; +import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -47,7 +48,6 @@ public class LogEntryEditorController { private Node parent; private LogEntryModel model; - private LogEntryCompletionHandler completionHandler; private Logger logger = Logger.getLogger(LogEntryEditorController.class.getName()); @@ -66,16 +66,17 @@ public class LogEntryEditorController { @FXML private AttachmentsViewController attachmentsViewController; + private Optional logEntryResult = Optional.empty(); + private ExecutorService executorService; private SimpleBooleanProperty progressIndicatorVisibility = new SimpleBooleanProperty(false); - public LogEntryEditorController(Node parent, LogEntryModel model, LogEntryCompletionHandler logEntryCompletionHandler){ + public LogEntryEditorController(Node parent, LogEntryModel model){ this.parent = parent; this.model = model; - this.completionHandler = logEntryCompletionHandler; this.executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); } @@ -108,9 +109,7 @@ public void submit(){ Future future = executorService.submit(() -> model.submitEntry()); LogEntry result = future.get(); if(result != null){ - if(completionHandler != null){ - completionHandler.handleResult(result); - } + logEntryResult = Optional.of(result); cancel(); } } catch (InterruptedException e) { @@ -139,4 +138,11 @@ private void localize(){ cancel.setText(Messages.Cancel); cancel.setTooltip(new Tooltip(Messages.CancelTooltip)); } + + /** + * @return The result of the log entry submission, potentially empty (e.g. user cancels edit) + */ + public Optional getLogEntryResult(){ + return logEntryResult; + } } diff --git a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorStage.java b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorStage.java index 5afecf1bc0..7dcd9e1113 100644 --- a/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorStage.java +++ b/app/logbook/ui/src/main/java/org/phoebus/logbook/ui/write/LogEntryEditorStage.java @@ -24,31 +24,39 @@ import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; +import org.phoebus.logbook.LogEntry; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; +/** + * {@link Stage} subclass rendering a UI for the purpose of editing/submitting a {@link LogEntry}. + * Callers that need to handle the outcome (i.e. when the {@link Stage} is closed) should + * call first call {@link #showAndWait()} and then get a potential result using {@link #getLogEntryResult()}. + */ public class LogEntryEditorStage extends Stage { - /** + private LogEntryEditorController logEntryEditorController; + /** * A stand-alone window containing components needed to create a logbook entry. * @param parent The {@link Node} from which the user - through context menu or application menu - requests a new * logbook entry. - * @param logEntryModel Pre-populated data for the log entry, e.g. date and (optionally) screen shot. - * @param completionHandler If non-null, called when the submission to the logbook service has completed. + * @param logEntryModel Pre-populated data for the log entry, e.g. date and (optionally) screenshot. */ - public LogEntryEditorStage(Node parent, LogEntryModel logEntryModel, LogEntryCompletionHandler completionHandler) + public LogEntryEditorStage(Node parent, LogEntryModel logEntryModel) { initModality(Modality.APPLICATION_MODAL); FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("LogEntryEditor.fxml")); fxmlLoader.setControllerFactory(clazz -> { try { if(clazz.isAssignableFrom(LogEntryEditorController.class)){ - return clazz.getConstructor(Node.class, LogEntryModel.class, LogEntryCompletionHandler.class) - .newInstance(parent, logEntryModel, completionHandler); + logEntryEditorController = (LogEntryEditorController) clazz.getConstructor(Node.class, LogEntryModel.class) + .newInstance(parent, logEntryModel); + return logEntryEditorController; } else if(clazz.isAssignableFrom(FieldsViewController.class)){ return clazz.getConstructor(LogEntryModel.class) @@ -74,4 +82,12 @@ else if(clazz.isAssignableFrom(AttachmentsViewController.class)){ Scene scene = new Scene(fxmlLoader.getRoot()); setScene(scene); } + + /** + * + * @return A potentially empty result of {@link LogEntry} submission. + */ + public Optional getLogEntryResult(){ + return logEntryEditorController.getLogEntryResult(); + } } diff --git a/app/logbook/ui/src/test/java/org/phoebus/logbook/ui/write/LogEntryEditorStageDemo.java b/app/logbook/ui/src/test/java/org/phoebus/logbook/ui/write/LogEntryEditorStageDemo.java index fabcf531cd..8d5093f08f 100644 --- a/app/logbook/ui/src/test/java/org/phoebus/logbook/ui/write/LogEntryEditorStageDemo.java +++ b/app/logbook/ui/src/test/java/org/phoebus/logbook/ui/write/LogEntryEditorStageDemo.java @@ -31,7 +31,7 @@ public void start(Stage primaryStage) throws Exception Scene scene = new Scene(root); primaryStage.setScene(scene); - new LogEntryEditorStage(root, new LogEntryModel(), null).show(); + new LogEntryEditorStage(root, new LogEntryModel()).show(); } } diff --git a/app/pace/src/main/java/org/csstudio/display/pace/PACEInstance.java b/app/pace/src/main/java/org/csstudio/display/pace/PACEInstance.java index 002c12cbe8..05c83f3e6d 100644 --- a/app/pace/src/main/java/org/csstudio/display/pace/PACEInstance.java +++ b/app/pace/src/main/java/org/csstudio/display/pace/PACEInstance.java @@ -14,6 +14,7 @@ import java.time.Instant; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.logging.Level; import org.csstudio.display.pace.gui.GUI; @@ -103,36 +104,31 @@ private void doSaveChanges(final JobMonitor monitor) LogEntryModel logEntryModel = new LogEntryModel(entry); - new LogEntryEditorStage(gui, logEntryModel, logEntry -> { - if (logEntry != null) - { - final String user = logEntryModel.getUsername(); - try - { // Change PVs - model.saveUserValues(user); - // On success, clear user values - model.clearUserValues(); - } - catch (Exception ex) - { - logger.log(Level.WARNING, "Save failed", ex); - // At least some saves failed, to revert - try - { - model.revertOriginalValues(); - } - catch (Exception ex2) - { - // Since saving didn't work, restoral will also fail. - // Hopefully those initial PVs that did get updated will - // also be restored... - logger.log(Level.WARNING, "Restore failed", ex2); - } - ExceptionDetailsErrorDialog.openError(gui, Messages.SaveError, Messages.PVWriteError, ex); + LogEntryEditorStage logEntryEditorStage = new LogEntryEditorStage(gui, logEntryModel); + logEntryEditorStage.showAndWait(); + Optional logEntryResult = logEntryEditorStage.getLogEntryResult(); + if (logEntryResult.isPresent()) { + final String user = logEntryModel.getUsername(); + try { // Change PVs + model.saveUserValues(user); + + // On success, clear user values + model.clearUserValues(); + } catch (Exception ex) { + logger.log(Level.WARNING, "Save failed", ex); + // At least some saves failed, to revert + try { + model.revertOriginalValues(); + } catch (Exception ex2) { + // Since saving didn't work, restoral will also fail. + // Hopefully those initial PVs that did get updated will + // also be restored... + logger.log(Level.WARNING, "Restore failed", ex2); } + ExceptionDetailsErrorDialog.openError(gui, Messages.SaveError, Messages.PVWriteError, ex); } - }).show(); + } } /** Create the 'body', the main text of the ELog entry which From 2324aa113d763f654cc3a76de97b1e36c16dfaea Mon Sep 17 00:00:00 2001 From: georgweiss Date: Mon, 25 Nov 2024 08:10:41 +0100 Subject: [PATCH 5/8] Reuse of olog entry editor to support update case --- .../olog/ui/LogEntryTableViewController.java | 9 +- .../ui/write/LogEntryEditorController.java | 51 +- .../olog/ui/write/LogEntryEditorStage.java | 9 +- .../ui/write/LogEntryUpdateController.java | 709 ------------------ .../olog/ui/write/LogEntryUpdateStage.java | 116 --- .../logbook/olog/ui/write/LogEntryUpdate.fxml | 232 ------ 6 files changed, 32 insertions(+), 1094 deletions(-) delete mode 100644 app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java delete mode 100644 app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java delete mode 100644 app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryUpdate.fxml diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java index 1d82b573ce..8a0429e77e 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/LogEntryTableViewController.java @@ -50,7 +50,6 @@ import org.phoebus.logbook.olog.ui.query.OlogQueryManager; import org.phoebus.logbook.olog.ui.write.EditMode; import org.phoebus.logbook.olog.ui.write.LogEntryEditorStage; -//import org.phoebus.logbook.olog.ui.write.LogEntryUpdateStage; import org.phoebus.olog.es.api.model.LogGroupProperty; import org.phoebus.olog.es.api.model.OlogLog; import org.phoebus.security.store.SecureStore; @@ -186,16 +185,12 @@ public void initialize() { MenuItem menuItemNewLogEntry = new MenuItem(Messages.NewLogEntry); menuItemNewLogEntry.acceleratorProperty().setValue(new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN)); - menuItemNewLogEntry.setOnAction(ae -> { - new LogEntryEditorStage(new OlogLog(), null, EditMode.NEW_LOG_ENTRY).showAndWait(); - }); + menuItemNewLogEntry.setOnAction(ae -> new LogEntryEditorStage(new OlogLog(), null, EditMode.NEW_LOG_ENTRY).showAndWait()); MenuItem menuItemUpdateLogEntry = new MenuItem(Messages.UpdateLogEntry); menuItemUpdateLogEntry.visibleProperty().bind(Bindings.createBooleanBinding(() -> selectedLogEntries.size() == 1, selectedLogEntries)); menuItemUpdateLogEntry.acceleratorProperty().setValue(new KeyCodeCombination(KeyCode.U, KeyCombination.CONTROL_DOWN)); - menuItemUpdateLogEntry.setOnAction(ae -> { - new LogEntryEditorStage(selectedLogEntries.get(0), null, EditMode.UPDATE_LOG_ENTRY).show(); - }); + menuItemUpdateLogEntry.setOnAction(ae -> new LogEntryEditorStage(selectedLogEntries.get(0), null, EditMode.UPDATE_LOG_ENTRY).show()); contextMenu.getItems().addAll(groupSelectedEntries, menuItemShowHideAll, menuItemNewLogEntry); if (LogbookUIPreferences.log_entry_update_support) { diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java index df35ea52ad..6702e2854e 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorController.java @@ -230,11 +230,13 @@ public class LogEntryEditorController { */ private String originalTitle = ""; - private EditMode editMode; + private final EditMode editMode; + /** + * Result of a submission, caller may use this to take further action once a {@link LogEntry} has been created. + */ private Optional logEntryResult = Optional.empty(); - public LogEntryEditorController(LogEntry logEntry, LogEntry inReplyTo, EditMode editMode) { this.replyTo = inReplyTo; this.logFactory = LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory); @@ -496,12 +498,6 @@ public LogTemplate fromString(String s) { } }); - JobManager.schedule("Get templates", monitor -> { - LogClient logClient = logFactory.getLogClient(); - Collection templates = logClient.getTemplates(); - Platform.runLater(() -> templateSelector.getItems().addAll(templates)); - }); - // Note: logbooks and tags are retrieved asynchronously from service getServerSideStaticData(); } @@ -547,7 +543,9 @@ public void submit() { ologLog.setLevel(selectedLevelProperty.get()); ologLog.setLogbooks(getSelectedLogbooks()); ologLog.setTags(getSelectedTags()); - ologLog.setAttachments(attachmentsEditorController.getAttachments()); + if(editMode.equals(EditMode.NEW_LOG_ENTRY)){ + ologLog.setAttachments(attachmentsEditorController.getAttachments()); + } ologLog.setProperties(logPropertiesEditorController.getProperties()); LogClient logClient = @@ -560,23 +558,23 @@ public void submit() { } // Not dirty anymore... isDirty = false; - if (logEntryResult.isPresent()) { - // Set username and password in secure store if submission of log entry completes successfully - if (Preferences.save_credentials) { - // Get the SecureStore. Store username and password. - try { - SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = - new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, usernameProperty.get(), passwordProperty.get()); - store.setScopedAuthentication(scopedAuthenticationToken); - } catch (Exception ex) { - logger.log(Level.WARNING, "Secure Store file not found.", ex); - } + + // Set username and password in secure store if submission of log entry completes successfully + if (Preferences.save_credentials) { + // Get the SecureStore. Store username and password. + try { + SecureStore store = new SecureStore(); + ScopedAuthenticationToken scopedAuthenticationToken = + new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, usernameProperty.get(), passwordProperty.get()); + store.setScopedAuthentication(scopedAuthenticationToken); + } catch (Exception ex) { + logger.log(Level.WARNING, "Secure Store file not found.", ex); } - attachmentsEditorController.deleteTemporaryFiles(); - // This will close the editor - Platform.runLater(this::cancel); } + attachmentsEditorController.deleteTemporaryFiles(); + // This will close the editor + Platform.runLater(this::cancel); + } catch (LogbookException e) { logger.log(Level.WARNING, "Unable to submit log entry", e); Platform.runLater(() -> { @@ -768,6 +766,9 @@ private void getServerSideStaticData() { } catch (Exception e) { logger.log(Level.WARNING, "Failed to get or parse response from server info request", e); } + + Collection templates = logClient.getTemplates(); + Platform.runLater(() -> templateSelector.getItems().addAll(templates)); }); } @@ -832,7 +833,7 @@ private boolean checkConnectivity() { } } - public Optional getLogEntryResult(){ + public Optional getLogEntryResult() { return logEntryResult; } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java index 97c0d57b9b..6a208d674c 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryEditorStage.java @@ -102,11 +102,10 @@ public LogEntryEditorStage(LogEntry logEntry, LogEntry replyTo, EditMode editMod we.consume(); handleCloseEditor(logEntryEditorController.isDirty(), fxmlLoader.getRoot()); }); - if (replyTo == null) { - setTitle(Messages.NewLogEntry); - } - else { - setTitle(Messages.ReplyToLogEntry); + + switch (editMode){ + case NEW_LOG_ENTRY -> setTitle(replyTo == null ? Messages.NewLogEntry : Messages.EditLogEntry); + case UPDATE_LOG_ENTRY -> setTitle(Messages.EditLogEntry); } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java deleted file mode 100644 index 5300ad614d..0000000000 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateController.java +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright (C) 2022 European Spallation Source ERIC. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -package org.phoebus.logbook.olog.ui.write; - -import javafx.application.Platform; -import javafx.beans.binding.Bindings; -import javafx.beans.property.ReadOnlyBooleanProperty; -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.Side; -import javafx.scene.control.*; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; -import org.phoebus.framework.jobs.JobManager; -import org.phoebus.framework.selection.SelectionService; -import org.phoebus.logbook.*; -import org.phoebus.logbook.olog.ui.*; -import org.phoebus.logbook.olog.ui.menu.SendToLogBookApp; -import org.phoebus.olog.es.api.OlogProperties; -import org.phoebus.olog.es.api.model.OlogAttachment; -import org.phoebus.olog.es.api.model.OlogLog; -import org.phoebus.security.store.SecureStore; -import org.phoebus.security.tokens.AuthenticationScope; -import org.phoebus.security.tokens.ScopedAuthenticationToken; -import org.phoebus.security.tokens.SimpleAuthenticationToken; -import org.phoebus.ui.Preferences; -import org.phoebus.ui.dialog.ListSelectionPopOver; -import org.phoebus.ui.javafx.ImageCache; -import org.phoebus.util.time.TimestampFormats; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.time.Instant; -import java.util.*; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * Controller for the {@link LogEntryUpdateStage}. - */ -public class LogEntryUpdateController { - - private final Logger logger = Logger.getLogger(LogEntryUpdateController.class.getName()); - - @FXML - private VBox editorPane; - @FXML - private VBox errorPane; - @FXML - private Button submitButton; - @FXML - private Button cancelButton; - @FXML - private ProgressIndicator progressIndicator; - @FXML - private Label completionMessageLabel; - - @SuppressWarnings("unused") - @FXML - private AttachmentsViewController attachmentsViewController; - @SuppressWarnings("unused") - @FXML - private LogPropertiesEditorController logPropertiesEditorController; - - @FXML - private Label userFieldLabel; - @FXML - private Label passwordFieldLabel; - @FXML - private TextField userField; - @FXML - private PasswordField passwordField; - @FXML - private Label levelLabel; - @FXML - private TextField dateField; - @FXML - private ComboBox levelSelector; - @FXML - private Label titleLabel; - @FXML - private TextField titleField; - @FXML - private TextArea textArea; - @FXML - private Button addLogbooks; - @FXML - private Button addTags; - @FXML - private ToggleButton logbooksDropdownButton; - @FXML - private ToggleButton tagsDropdownButton; - @FXML - private Label logbooksLabel; - @FXML - private TextField logbooksSelection; - @FXML - private TextField tagsSelection; - - private final ContextMenu logbookDropDown = new ContextMenu(); - private final ContextMenu tagDropDown = new ContextMenu(); - - private final ObservableList selectedLogbooks = FXCollections.observableArrayList(); - private final ObservableList selectedTags = FXCollections.observableArrayList(); - - private ObservableList availableLogbooksAsStringList; - private ObservableList availableTagsAsStringList; - private Collection availableLogbooks; - private Collection availableTags; - - private ListSelectionPopOver tagsPopOver; - private ListSelectionPopOver logbooksPopOver; - - private final ObservableList availableLevels = FXCollections.observableArrayList(); - private final SimpleStringProperty titleProperty = new SimpleStringProperty(); - private final SimpleStringProperty descriptionProperty = new SimpleStringProperty(); - private final SimpleStringProperty selectedLevelProperty = new SimpleStringProperty(); - private final SimpleStringProperty usernameProperty = new SimpleStringProperty(); - private final SimpleStringProperty passwordProperty = new SimpleStringProperty(); - - private final LogEntry logEntry; - - private final SimpleBooleanProperty updateCredentials = new SimpleBooleanProperty(); - private final ReadOnlyBooleanProperty updateCredentialsProperty; - private final SimpleBooleanProperty inputValid = new SimpleBooleanProperty(false); - - private final LogFactory logFactory; - - private final SimpleBooleanProperty submissionInProgress = - new SimpleBooleanProperty(false); - - private final Long logId; - - /** - * Indicates if user has started editing. Only title and body are used to define dirty state. - */ - private boolean isDirty = false; - - /** - * Used to determine if a log entry is dirty. For a new log entry, comparison is made to empty string, for - * the reply case the original title is copied to this field. - */ - private String originalTitle = ""; - - - public LogEntryUpdateController(LogEntry logEntry) { - this.logId = logEntry.getId(); - this.logFactory = LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory); - updateCredentialsProperty = updateCredentials; - this.logEntry = logEntry; - } - - @FXML - public void initialize() { - - // This could be configured in the fxml, but then these UI components would not be visible - // in Scene Builder. - completionMessageLabel.textProperty().set(""); - progressIndicator.visibleProperty().bind(submissionInProgress); - - // Remote log service not reachable, so show error pane. - if (!checkConnectivity()) { - errorPane.visibleProperty().set(true); - editorPane.disableProperty().set(true); - return; - } - - submitButton.disableProperty().bind(Bindings.createBooleanBinding(() -> - !inputValid.get() || submissionInProgress.get(), - inputValid, submissionInProgress)); - completionMessageLabel.visibleProperty() - .bind(Bindings.createBooleanBinding(() -> completionMessageLabel.textProperty().isNotEmpty().get() && !submissionInProgress.get(), - completionMessageLabel.textProperty(), submissionInProgress)); - - cancelButton.disableProperty().bind(submissionInProgress); - - userField.textProperty().bindBidirectional(usernameProperty); - userField.textProperty().addListener((changeListener, oldVal, newVal) -> - { - if (newVal.trim().isEmpty()) - userFieldLabel.setTextFill(Color.RED); - else - userFieldLabel.setTextFill(Color.BLACK); - }); - - passwordField.textProperty().bindBidirectional(passwordProperty); - passwordField.textProperty().addListener((changeListener, oldVal, newVal) -> - { - if (newVal.trim().isEmpty()) - passwordFieldLabel.setTextFill(Color.RED); - else - passwordFieldLabel.setTextFill(Color.BLACK); - }); - - updateCredentialsProperty.addListener((changeListener, oldVal, newVal) -> - { - // This call back should be running on a background thread. Perform contents on JavaFX application thread. - Platform.runLater(() -> - { - userField.setText(usernameProperty.get()); - passwordField.setText(passwordProperty.get()); - - // Put focus on first required field that is empty. - if (userField.getText().isEmpty()) { - userField.requestFocus(); - } else if (passwordField.getText().isEmpty()) { - passwordField.requestFocus(); - } else if (titleField.getText() == null || titleField.getText().isEmpty()) { - titleField.requestFocus(); - } else { - textArea.requestFocus(); - } - }); - }); - if (Preferences.save_credentials) { - fetchStoredUserCredentials(); - } - - levelLabel.setText(LogbookUIPreferences.level_field_name); - // Sites may wish to define a different meaning and name for the "level" field. - OlogProperties ologProperties = new OlogProperties(); - String[] levelList = ologProperties.getPreferenceValue("levels").split(","); - availableLevels.addAll(Arrays.asList(levelList)); - levelSelector.setItems(availableLevels); - selectedLevelProperty.set(logEntry.getLevel() != null ? logEntry.getLevel() : availableLevels.get(0)); - - levelSelector.getSelectionModel().select(selectedLevelProperty.get()); - - dateField.setText(TimestampFormats.DATE_FORMAT.format(Instant.now())); - - titleField.textProperty().bindBidirectional(titleProperty); - titleProperty.addListener((changeListener, oldVal, newVal) -> - { - if (newVal.trim().isEmpty()) { - titleLabel.setTextFill(Color.RED); - } else { - titleLabel.setTextFill(Color.BLACK); - } - if (!newVal.equals(originalTitle)) { - isDirty = true; - } - }); - titleProperty.set(logEntry.getTitle()); - - textArea.textProperty().bindBidirectional(descriptionProperty); - if (logEntry.getSource() != null) { - descriptionProperty.set(logEntry.getSource()); - } - else if (logEntry.getDescription() != null) { - descriptionProperty.set(logEntry.getDescription()); - } - else { - descriptionProperty.set(""); - } - descriptionProperty.addListener((observable, oldValue, newValue) -> isDirty = true); - - Image tagIcon = ImageCache.getImage(LogEntryUpdateController.class, "/icons/add_tag.png"); - Image logbookIcon = ImageCache.getImage(LogEntryUpdateController.class, "/icons/logbook-16.png"); - Image downIcon = ImageCache.getImage(LogEntryUpdateController.class, "/icons/down_triangle.png"); - - addLogbooks.setGraphic(new ImageView(logbookIcon)); - addTags.setGraphic(new ImageView(tagIcon)); - logbooksDropdownButton.setGraphic(new ImageView(downIcon)); - tagsDropdownButton.setGraphic(new ImageView(downIcon)); - - logbooksSelection.textProperty().addListener((changeListener, oldVal, newVal) -> - { - if (newVal.trim().isEmpty()) - logbooksLabel.setTextFill(Color.RED); - else - logbooksLabel.setTextFill(Color.BLACK); - }); - - logbooksSelection.textProperty().bind(Bindings.createStringBinding(() -> { - if (selectedLogbooks.isEmpty()) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - selectedLogbooks.forEach(l -> stringBuilder.append(l).append(", ")); - String text = stringBuilder.toString(); - return text.substring(0, text.length() - 2); - }, selectedLogbooks)); - - tagsSelection.textProperty().bind(Bindings.createStringBinding(() -> { - if (selectedTags.isEmpty()) { - return ""; - } - StringBuilder stringBuilder = new StringBuilder(); - selectedTags.forEach(l -> stringBuilder.append(l).append(", ")); - String text = stringBuilder.toString(); - return text.substring(0, text.length() - 2); - }, selectedTags)); - - logbooksDropdownButton.focusedProperty().addListener((changeListener, oldVal, newVal) -> - { - if (!newVal && !tagDropDown.isShowing() && !logbookDropDown.isShowing()) - logbooksDropdownButton.setSelected(false); - }); - - tagsDropdownButton.focusedProperty().addListener((changeListener, oldVal, newVal) -> - { - if (!newVal && !tagDropDown.isShowing() && !tagDropDown.isShowing()) - tagsDropdownButton.setSelected(false); - }); - - inputValid.bind(Bindings.createBooleanBinding(() -> titleProperty.get() != null && !titleProperty.get().isEmpty() && - usernameProperty.get() != null && !usernameProperty.get().isEmpty() && - passwordProperty.get() != null && !passwordProperty.get().isEmpty() && - !selectedLogbooks.isEmpty(), - titleProperty, usernameProperty, passwordProperty, selectedLogbooks)); - - tagsPopOver = ListSelectionPopOver.create( - (tags, popOver) -> { - setSelectedTags(tags, selectedTags); - if (popOver.isShowing()) { - popOver.hide(); - } - }, - (tags, popOver) -> popOver.hide() - ); - logbooksPopOver = ListSelectionPopOver.create( - (logbooks, popOver) -> { - setSelectedLogbooks(logbooks, selectedLogbooks); - if (popOver.isShowing()) { - popOver.hide(); - } - }, - (logbooks, popOver) -> popOver.hide() - ); - - selectedTags.addListener((ListChangeListener) change -> { - List newSelection = new ArrayList<>(change.getList()); - tagsPopOver.setAvailable(availableTagsAsStringList, newSelection); - tagsPopOver.setSelected(newSelection); - }); - - selectedLogbooks.addListener((ListChangeListener) change -> { - List newSelection = new ArrayList<>(change.getList()); - logbooksPopOver.setAvailable(availableLogbooksAsStringList, newSelection); - logbooksPopOver.setSelected(newSelection); - }); - - // Note: logbooks and tags are retrieved asynchronously from service - setupLogbooksAndTags(); - retrieveAttachments(); - } - - /** - * Handler for Cancel button. Note that any selections in the {@link SelectionService} are - * cleared to prevent next launch of {@link SendToLogBookApp} - * to pick them up. - */ - @FXML - public void cancel() { - // Need to clear selections. - SelectionService.getInstance().clearSelection(""); - ((LogEntryUpdateStage) cancelButton.getScene().getWindow()).handleCloseEditor(isDirty, editorPane); - } - - @FXML - public void showHelp() { - new HelpViewer(LogbookUIPreferences.markup_help).show(); - } - - /** - * Handler for HTML preview button - */ - @FXML - public void showHtmlPreview() { - new PreviewViewer(getDescription(), attachmentsViewController.getAttachments()).show(); - } - - - @FXML - public void submit() { - - submissionInProgress.set(true); - - JobManager.schedule("Submit Log Entry Update", monitor -> { - OlogLog ologLog = new OlogLog(); - ologLog.setId(logId); - ologLog.setTitle(getTitle()); - ologLog.setDescription(getDescription()); - ologLog.setLevel(selectedLevelProperty.get()); - ologLog.setLogbooks(getSelectedLogbooks()); - ologLog.setTags(getSelectedTags()); -// ologLog.setAttachments(attachmentsViewController.getAttachments()); - ologLog.setProperties(logPropertiesEditorController.getProperties()); - - LogClient logClient = - logFactory.getLogClient(new SimpleAuthenticationToken(usernameProperty.get(), passwordProperty.get())); - LogEntry result; - try { - result = logClient.update(ologLog); - // Not dirty any more... - isDirty = false; - if (result != null) { - // Set username and password in secure store if submission of log entry completes successfully - if (Preferences.save_credentials) { - // Get the SecureStore. Store username and password. - try { - SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = - new ScopedAuthenticationToken(AuthenticationScope.LOGBOOK, usernameProperty.get(), passwordProperty.get()); - store.setScopedAuthentication(scopedAuthenticationToken); - } catch (Exception ex) { - logger.log(Level.WARNING, "Secure Store file not found.", ex); - } - } - // This will close the editor - Platform.runLater(this::cancel); - } - } catch (LogbookException e) { - logger.log(Level.WARNING, "Unable to submit log entry", e); - Platform.runLater(() -> { - if (e.getCause() != null && e.getCause().getMessage() != null) { - completionMessageLabel.textProperty().setValue(e.getCause().getMessage()); - } else if (e.getMessage() != null) { - completionMessageLabel.textProperty().setValue(e.getMessage()); - } else { - completionMessageLabel.textProperty().setValue(org.phoebus.logbook.Messages.SubmissionFailed); - } - }); - } - submissionInProgress.set(false); - }); - } - - @FXML - public void setLevel() { - selectedLevelProperty.set(levelSelector.getSelectionModel().getSelectedItem()); - } - - public String getTitle() { - return titleProperty.get(); - } - - public String getDescription() { - return descriptionProperty.get(); - } - - @FXML - public void addLogbooks() { - logbooksPopOver.show(addLogbooks); - } - - private void addSelectedLogbook(String logbookName) { - selectedLogbooks.add(logbookName); - updateDropDown(logbookDropDown, logbookName, true); - } - - private void removeSelectedLogbook(String logbookName) { - selectedLogbooks.remove(logbookName); - updateDropDown(logbookDropDown, logbookName, false); - } - - private void setSelectedLogbooks(List proposedLogbooks, List existingLogbooks) { - setSelected(proposedLogbooks, existingLogbooks, this::addSelectedLogbook, this::removeSelectedLogbook); - } - - private void setSelected(List proposed, List existing, Consumer addFunction, Consumer removeFunction) { - List addedTags = proposed.stream() - .filter(tag -> !existing.contains(tag)) - .collect(Collectors.toList()); - List removedTags = existing.stream() - .filter(tag -> !proposed.contains(tag)) - .collect(Collectors.toList()); - addedTags.forEach(addFunction); - removedTags.forEach(removeFunction); - } - - @FXML - public void selectLogbooks() { - if (logbooksDropdownButton.isSelected()) { - logbookDropDown.show(logbooksSelection, Side.BOTTOM, 0, 0); - } else { - logbookDropDown.hide(); - } - } - - @FXML - public void addTags() { - tagsPopOver.show(addTags); - } - - private void addSelectedTag(String tagName) { - selectedTags.add(tagName); - updateDropDown(tagDropDown, tagName, true); - } - - private void removeSelectedTag(String tagName) { - selectedTags.remove(tagName); - updateDropDown(tagDropDown, tagName, false); - } - - private void setSelectedTags(List proposedTags, List existingTags) { - setSelected(proposedTags, existingTags, this::addSelectedTag, this::removeSelectedTag); - } - - @FXML - public void selectTags() { - if (tagsDropdownButton.isSelected()) { - tagDropDown.show(tagsSelection, Side.BOTTOM, 0, 0); - } else { - tagDropDown.hide(); - } - } - - public List getSelectedLogbooks() { - return availableLogbooks.stream().filter(l -> selectedLogbooks.contains(l.getName())).collect(Collectors.toList()); - } - - public List getSelectedTags() { - return availableTags.stream().filter(t -> selectedTags.contains(t.getName())).collect(Collectors.toList()); - } - - /** - * Retrieves logbooks and tags from service and populates all the data structures that depend - * on the result. The call to the remote service is asynchronous. - */ - private void setupLogbooksAndTags() { - JobManager.schedule("Fetch Logbooks and Tags", monitor -> - { - LogClient logClient = - LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory).getLogClient(); - availableLogbooks = logClient.listLogbooks(); - availableLogbooksAsStringList = - FXCollections.observableArrayList(availableLogbooks.stream().map(Logbook::getName).collect(Collectors.toList())); - Collections.sort(availableLogbooksAsStringList); - - List preSelectedLogbooks = - logEntry.getLogbooks().stream().map(Logbook::getName).collect(Collectors.toList()); - List defaultLogbooks = Arrays.asList(LogbookUIPreferences.default_logbooks); - availableLogbooksAsStringList.forEach(logbook -> { - CheckBox checkBox = new CheckBox(logbook); - CustomMenuItem newLogbook = new CustomMenuItem(checkBox); - newLogbook.setHideOnClick(false); - checkBox.setOnAction(e -> { - CheckBox source = (CheckBox) e.getSource(); - String text = source.getText(); - if (source.isSelected()) { - selectedLogbooks.add(text); - } else { - selectedLogbooks.remove(text); - } - }); - if (!preSelectedLogbooks.isEmpty() && preSelectedLogbooks.contains(logbook)) { - checkBox.setSelected(preSelectedLogbooks.contains(logbook)); - selectedLogbooks.add(logbook); - } else if (defaultLogbooks.contains(logbook) && selectedLogbooks.isEmpty()) { - checkBox.setSelected(defaultLogbooks.contains(logbook)); - selectedLogbooks.add(logbook); - } - logbookDropDown.getItems().add(newLogbook); - }); - - availableTags = logClient.listTags(); - availableTagsAsStringList = - FXCollections.observableArrayList(availableTags.stream().map(Tag::getName).collect(Collectors.toList())); - Collections.sort(availableLogbooksAsStringList); - - List preSelectedTags = - logEntry.getTags().stream().map(Tag::getName).collect(Collectors.toList()); - availableTagsAsStringList.forEach(tag -> { - CheckBox checkBox = new CheckBox(tag); - CustomMenuItem newTag = new CustomMenuItem(checkBox); - newTag.setHideOnClick(false); - checkBox.setOnAction(e -> { - CheckBox source = (CheckBox) e.getSource(); - String text = source.getText(); - if (source.isSelected()) { - selectedTags.add(text); - } else { - selectedTags.remove(text); - } - }); - checkBox.setSelected(preSelectedTags.contains(tag)); - if (preSelectedTags.contains(tag)) { - selectedTags.add(tag); - } - tagDropDown.getItems().add(newTag); - }); - - tagsPopOver.setAvailable(availableTagsAsStringList, selectedTags); - tagsPopOver.setSelected(selectedTags); - logbooksPopOver.setAvailable(availableLogbooksAsStringList, selectedLogbooks); - logbooksPopOver.setSelected(selectedLogbooks); - - }); - } - - private void retrieveAttachments() { - JobManager.schedule("Fetch attachment data", monitor -> { - - LogClient logClient = - LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory).getLogClient(); - Collection attachments = logEntry.getAttachments().stream() - .filter((attachment) -> attachment.getName() != null && !attachment.getName().isEmpty()) - .map((attachment) -> { - OlogAttachment fileAttachment = new OlogAttachment(); - fileAttachment.setContentType(attachment.getContentType()); - fileAttachment.setThumbnail(false); - fileAttachment.setFileName(attachment.getName()); - try { - Path temp = Files.createTempFile("phoebus", attachment.getName()); - Files.copy(logClient.getAttachment(logEntry.getId(), attachment.getName()), temp, StandardCopyOption.REPLACE_EXISTING); - fileAttachment.setFile(temp.toFile()); - temp.toFile().deleteOnExit(); - } catch (LogbookException | IOException e) { - Logger.getLogger(SingleLogEntryDisplayController.class.getName()) - .log(Level.WARNING, "Failed to retrieve attachment " + fileAttachment.getFileName(), e); - } - return fileAttachment; - }).collect(Collectors.toList()); - // Update UI - Platform.runLater(() -> { - attachmentsViewController.setAttachments(attachments); - }); - }); - } - - public void fetchStoredUserCredentials() { - // Perform file IO on background thread. - JobManager.schedule("Access Secure Store", monitor -> - { - // Get the SecureStore. Retrieve username and password. - try { - SecureStore store = new SecureStore(); - ScopedAuthenticationToken scopedAuthenticationToken = store.getScopedAuthenticationToken(AuthenticationScope.LOGBOOK); - // Could be accessed from JavaFX Application Thread when updating, so synchronize. - synchronized (usernameProperty) { - usernameProperty.set(scopedAuthenticationToken == null ? "" : scopedAuthenticationToken.getUsername()); - } - synchronized (passwordProperty) { - passwordProperty.set(scopedAuthenticationToken == null ? "" : scopedAuthenticationToken.getPassword()); - } - // Let anyone listening know that their credentials are now out of date. - updateCredentials.set(true); - } catch (Exception ex) { - logger.log(Level.WARNING, "Secure Store file not found.", ex); - } - }); - } - - /** - * Updates the logbooks or tags context menu to reflect the state of selected logbooks and tags. - * - * @param contextMenu The context menu to update - * @param itemName The logbook or tag name identifying to a context menu item - * @param itemSelected Indicates whether to select or deselect. - */ - private void updateDropDown(ContextMenu contextMenu, String itemName, boolean itemSelected) { - for (MenuItem menuItem : contextMenu.getItems()) { - CustomMenuItem custom = (CustomMenuItem) menuItem; - CheckBox check = (CheckBox) custom.getContent(); - if (check.getText().equals(itemName)) { - check.setSelected(itemSelected); - break; - } - } - } - - public boolean isDirty() { - return isDirty; - } - - /** - * Checks connectivity to remote service by querying the info end-point. If connection fails, - * connectionError property is set to true, which should set opacity of the editor pane, and - * set visibility of error pane. - */ - private boolean checkConnectivity() { - LogClient logClient = LogService.getInstance().getLogFactories().get(LogbookPreferences.logbook_factory).getLogClient(); - try { - logClient.serviceInfo(); - return true; - } catch (Exception e) { - Logger.getLogger(SendToLogBookApp.class.getName()).warning("Failed to query logbook service, it may be off-line."); - return false; - } - } -} diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java deleted file mode 100644 index dab81fa79c..0000000000 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/write/LogEntryUpdateStage.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2019 European Spallation Source ERIC. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -package org.phoebus.logbook.olog.ui.write; - -import javafx.fxml.FXMLLoader; -import javafx.scene.Node; -import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.ButtonBar; -import javafx.scene.control.ButtonType; -import javafx.stage.Modality; -import javafx.stage.Stage; -import org.phoebus.framework.nls.NLS; -import org.phoebus.logbook.LogEntry; -import org.phoebus.logbook.olog.ui.AttachmentsViewController; -import org.phoebus.logbook.olog.ui.Messages; -import org.phoebus.ui.dialog.DialogHelper; - -import java.util.Collection; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - */ -public class LogEntryUpdateStage extends Stage { - private LogEntryUpdateController logEntryUpdateController; - /** - * A stand-alone window containing components needed to create a logbook entry. - * - * @param logEntry Pre-populated data for the log entry, e.g. date and (optionally) screen shot. - * @param completionHandler A completion handler called when service call completes. - */ - public LogEntryUpdateStage(LogEntry logEntry) { - - initModality(Modality.WINDOW_MODAL); - ResourceBundle resourceBundle = NLS.getMessages(Messages.class); - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("LogEntryUpdate.fxml"), resourceBundle); - fxmlLoader.setControllerFactory(clazz -> { - try { - if (clazz.isAssignableFrom(LogEntryUpdateController.class)) { - logEntryUpdateController = (LogEntryUpdateController) clazz.getConstructor(LogEntry.class) - .newInstance(logEntry); - return logEntryUpdateController; - } else if (clazz.isAssignableFrom(AttachmentsEditorController.class)) { - return clazz.getConstructor(LogEntry.class).newInstance(logEntry); - } else if (clazz.isAssignableFrom(AttachmentsViewController.class)) { - return clazz.getConstructor().newInstance(); - } else if (clazz.isAssignableFrom(LogPropertiesEditorController.class)) { - return clazz.getConstructor(Collection.class).newInstance(logEntry.getProperties()); - } - } catch (Exception e) { - Logger.getLogger(LogEntryUpdateStage.class.getName()).log(Level.SEVERE, "Failed to construct controller for log editor UI", e); - } - return null; - }); - - try { - fxmlLoader.load(); - } catch ( - Exception exception) { - Logger.getLogger(LogEntryUpdateStage.class.getName()).log(Level.WARNING, "Unable to load fxml for log entry editor UI", exception); - } - - Scene scene = new Scene(fxmlLoader.getRoot()); - setScene(scene); - scene.getWindow().setOnCloseRequest(we -> { - we.consume(); - handleCloseEditor(logEntryUpdateController.isDirty(), fxmlLoader.getRoot()); - }); - setTitle(Messages.EditLogEntry); - } - - /** - * Helper method to show a confirmation dialog if user closes/cancels log entry editor with "dirty" data. - * - * @param entryIsDirty Indicates if the log entry content (title or body, or both) have been changed. - * @param parent The {@link Node} used to determine the position of the dialog. - */ - public void handleCloseEditor(boolean entryIsDirty, Node parent) { - if (entryIsDirty) { - ButtonType discardChanges = new ButtonType(Messages.CloseRequestButtonDiscard, ButtonBar.ButtonData.OK_DONE); - ButtonType continueEditing = new ButtonType(Messages.CloseRequestButtonContinue, ButtonBar.ButtonData.CANCEL_CLOSE); - Alert alert = new Alert(AlertType.CONFIRMATION, - null, - discardChanges, - continueEditing); - alert.setHeaderText(Messages.CloseRequestHeader); - DialogHelper.positionDialog(alert, parent, -200, -300); - if (alert.showAndWait().get().getButtonData().equals(ButtonBar.ButtonData.OK_DONE)) { - close(); - } - } else { - close(); - } - } -} diff --git a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryUpdate.fxml b/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryUpdate.fxml deleted file mode 100644 index f5d54a1ce2..0000000000 --- a/app/logbook/olog/ui/src/main/resources/org/phoebus/logbook/olog/ui/write/LogEntryUpdate.fxml +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -