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 87e10f73f5..a259a46ee8 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 European Spallation Source ERIC. + * Copyright (C) 2024 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 @@ -43,6 +43,8 @@ public class LogEntryDisplayController { @FXML @SuppressWarnings("unused") private MergedLogEntryDisplayController mergedLogEntryDisplayController; + + private LogEntryTableViewController logEntryTableViewController; @FXML private ToggleButton showHideLogEntryGroupButton; @FXML @@ -90,7 +92,9 @@ public void showHideLogEntryGroup() { mergedLogEntryDisplayController.setLogSelectionHandler((logEntry) -> { Platform.runLater(() -> { currentViewProperty.set(SINGLE); - setLogEntry(logEntry); + if(logEntryTableViewController.selectLogEntry(logEntry)){ + singleLogEntryDisplayController.setLogEntry(logEntry); + } }); return null; }); @@ -136,8 +140,12 @@ public LogEntry getLogEntry() { */ public void updateLogEntry(LogEntry logEntry){ // Log entry display may be "empty", i.e. logEntryProperty not set yet - if(!logEntryProperty.isNull().get() && logEntryProperty.get().getId() == logEntry.getId()){ + if(!logEntryProperty.isNull().get() && logEntryProperty.get().getId().equals(logEntry.getId())){ setLogEntry(logEntry); } } + + public void setLogEntryTableViewController(LogEntryTableViewController logEntryTableViewController){ + this.logEntryTableViewController = logEntryTableViewController; + } } 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 3211a1458a..9cb6a534f8 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 @@ -14,21 +14,8 @@ import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Node; -import javafx.scene.control.Alert; +import javafx.scene.control.*; import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.ComboBox; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.control.MenuItem; -import javafx.scene.control.Pagination; -import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; @@ -39,12 +26,7 @@ import javafx.util.Duration; import javafx.util.StringConverter; import org.phoebus.framework.jobs.JobManager; -import org.phoebus.logbook.LogClient; -import org.phoebus.logbook.LogEntry; -import org.phoebus.logbook.LogService; -import org.phoebus.logbook.LogbookException; -import org.phoebus.logbook.LogbookPreferences; -import org.phoebus.logbook.SearchResult; +import org.phoebus.logbook.*; import org.phoebus.logbook.olog.ui.query.OlogQuery; import org.phoebus.logbook.olog.ui.query.OlogQueryManager; import org.phoebus.logbook.olog.ui.write.LogEntryEditorStage; @@ -58,8 +40,10 @@ import org.phoebus.ui.dialog.ExceptionDetailsErrorDialog; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -137,11 +121,12 @@ public LogEntryTableViewController(LogClient logClient, OlogQueryManager ologQue private final SearchParameters searchParameters; - private LogEntry selectedLogEntry; @FXML public void initialize() { + logEntryDisplayController.setLogEntryTableViewController(this); + advancedSearchViewController.setSearchCallback(this::search); configureComboBox(); @@ -171,7 +156,7 @@ public void initialize() { menuItemNewLogEntry.setOnAction(ae -> new LogEntryEditorStage(new OlogLog(), null, null).show()); MenuItem menuItemUpdateLogEntry = new MenuItem(Messages.UpdateLogEntry); - menuItemUpdateLogEntry.visibleProperty().bind(Bindings.createBooleanBinding(()-> selectedLogEntries.size() == 1, selectedLogEntries)); + 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()); @@ -195,8 +180,8 @@ public void initialize() { tableView.getColumns().clear(); tableView.setEditable(false); tableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + // Update detailed view, but only if selection contains a single item. if (newValue != null && tableView.getSelectionModel().getSelectedItems().size() == 1) { - selectedLogEntry = newValue.getLogEntry(); logEntryDisplayController.setLogEntry(newValue.getLogEntry()); } List logEntries = tableView.getSelectionModel().getSelectedItems() @@ -398,16 +383,16 @@ public String getQuery() { private void refresh() { if (this.searchResult != null) { + List selectedLogEntries = new ArrayList<>(tableView.getSelectionModel().getSelectedItems()); ObservableList logsList = FXCollections.observableArrayList(); - logsList.addAll(searchResult.getLogs().stream().map(le -> new TableViewListItem(le, showDetails.get())).collect(Collectors.toList())); + logsList.addAll(searchResult.getLogs().stream().map(le -> new TableViewListItem(le, showDetails.get())).toList()); tableView.setItems(logsList); - // This will ensure that if an entry was selected, it stays selected after the list has been - // updated from the search result, even if it is empty. - if (selectedLogEntry != null) { + // This will ensure that selected entries stay selected after the list has been + // updated from the search result. + for (TableViewListItem selectedItem : selectedLogEntries) { for (TableViewListItem item : tableView.getItems()) { - if (item.getLogEntry().getId().equals(selectedLogEntry.getId())) { + if (item.getLogEntry().getId().equals(selectedItem.getLogEntry().getId())) { Platform.runLater(() -> tableView.getSelectionModel().select(item)); - break; } } } @@ -537,10 +522,29 @@ public void showHelp() { * Handler for a {@link LogEntry} change, new or updated. * A search is triggered to make sure the result list reflects the change, and * the detail view controller is called to refresh, if applicable. - * @param logEntry + * + * @param logEntry A {@link LogEntry} */ - public void logEntryChanged(LogEntry logEntry){ + public void logEntryChanged(LogEntry logEntry) { search(); logEntryDisplayController.updateLogEntry(logEntry); } + + /** + * Selects a log entry as a result of an action outside the {@link TreeView}, but selection happens on the + * {@link TreeView} item, if it exists (match on log entry id). If it does not exist, selection is cleared + * anyway to indicate that user selected log entry is not visible in {@link TreeView}. + * @param logEntry User selected log entry. + * @return true if user selected log entry is present in {@link TreeView}, otherwise + * false. + */ + public boolean selectLogEntry(LogEntry logEntry){ + tableView.getSelectionModel().clearSelection(); + Optional optional = tableView.getItems().stream().filter(i -> i.getLogEntry().getId().equals(logEntry.getId())).findFirst(); + if(optional.isPresent()){ + tableView.getSelectionModel().select(optional.get()); + return true; + } + return false; + } } diff --git a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/MergedLogEntryDisplayController.java b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/MergedLogEntryDisplayController.java index 572d2263d5..06acca79bd 100644 --- a/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/MergedLogEntryDisplayController.java +++ b/app/logbook/olog/ui/src/main/java/org/phoebus/logbook/olog/ui/MergedLogEntryDisplayController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 European Spallation Source ERIC. + * Copyright (C) 2024 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 @@ -104,20 +104,7 @@ public void setLogSelectionHandler(Function handler){ * @param logEntry The log entry selected by user in the table/list view. */ public void setLogEntry(LogEntry logEntry) { - getLogEntries(logEntry); - } - - private void mergeAndRender() { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(""); - logEntries.forEach(l -> { - stringBuilder.append(createSeparator(l)); - stringBuilder.append("
"); - stringBuilder.append(toHtml(l.getSource())); - stringBuilder.append("
"); - }); - stringBuilder.append(""); - webEngine.loadContent(stringBuilder.toString()); + getLogEntriesAndMerge(logEntry); } /** @@ -129,7 +116,7 @@ private void mergeAndRender() { */ private String createSeparator(LogEntry logEntry) { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("
"); + stringBuilder.append("
"); stringBuilder.append(SECONDS_FORMAT.format(logEntry.getCreatedDate())).append(", "); stringBuilder.append(logEntry.getOwner()).append(", "); stringBuilder.append(logEntry.getTitle()); @@ -137,14 +124,14 @@ private String createSeparator(LogEntry logEntry) { stringBuilder.append(" *"); } stringBuilder.append("
").append(logEntry.getId()).append("
"); - if(logEntry.getAttachments().size() > 0){ + if(!logEntry.getAttachments().isEmpty()){ stringBuilder.append("
 
"); } stringBuilder.append("
"); return stringBuilder.toString(); } - private void getLogEntries(LogEntry logEntry) { + private void getLogEntriesAndMerge(LogEntry logEntry) { Optional property = logEntry.getProperties().stream() @@ -164,7 +151,16 @@ private void getLogEntries(LogEntry logEntry) { logger.log(Level.SEVERE, "Unable to locate log entry items using log entry group id " + id, e); } - mergeAndRender(); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(""); + logEntries.forEach(l -> { + stringBuilder.append(createSeparator(l)); + stringBuilder.append("
"); + stringBuilder.append(toHtml(l.getSource())); + stringBuilder.append("
"); + }); + stringBuilder.append(""); + webEngine.loadContent(stringBuilder.toString()); } public class JavaConnector { @@ -176,7 +172,7 @@ public class JavaConnector { * the String to convert */ @SuppressWarnings("unused") - public void toLowerCase(String value) { + public void select(String value) { Optional logEntry = logEntries.stream().filter(l -> Long.toString(l.getId()).equals(value)).findFirst(); if(logEntry.isEmpty()){ return;