diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index 7b2d27d1292..017c5d8b320 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -71,7 +71,7 @@ public class StateManager { private final ObservableList visibleSidePanes = FXCollections.observableArrayList(); private final ObjectProperty lastAutomaticFieldEditorEdit = new SimpleObjectProperty<>(); private final ObservableList searchHistory = FXCollections.observableArrayList(); - private final OptionalObjectProperty aiChatWindow = OptionalObjectProperty.empty(); + private final List aiChatWindows = new ArrayList<>(); public ObservableList getVisibleSidePaneComponents() { return visibleSidePanes; @@ -211,7 +211,7 @@ public void clearSearchHistory() { searchHistory.clear(); } - public OptionalObjectProperty getAiChatWindow() { - return aiChatWindow; + public List getAiChatWindows() { + return aiChatWindows; } } diff --git a/src/main/java/org/jabref/gui/ai/components/aichat/AiChatWindow.java b/src/main/java/org/jabref/gui/ai/components/aichat/AiChatWindow.java index 2ae892021ea..8359eec5f05 100644 --- a/src/main/java/org/jabref/gui/ai/components/aichat/AiChatWindow.java +++ b/src/main/java/org/jabref/gui/ai/components/aichat/AiChatWindow.java @@ -23,6 +23,9 @@ public class AiChatWindow extends BaseWindow { private final FilePreferences filePreferences; private final TaskExecutor taskExecutor; + // This field is used for finding an existing AI chat window when user wants to chat with the same group again. + private String chatName; + public AiChatWindow(AiService aiService, DialogService dialogService, AiPreferences aiPreferences, @@ -38,6 +41,7 @@ public AiChatWindow(AiService aiService, public void setChat(StringProperty name, ObservableList chatHistory, BibDatabaseContext bibDatabaseContext, ObservableList entries) { setTitle(Localization.lang("AI chat with %0", name.getValue())); + chatName = name.getValue(); setScene( new Scene( new AiChatGuardedComponent( @@ -56,4 +60,8 @@ public void setChat(StringProperty name, ObservableList chatHistory ) ); } + + public String getChatName() { + return chatName; + } } diff --git a/src/main/java/org/jabref/logic/ai/AiService.java b/src/main/java/org/jabref/logic/ai/AiService.java index 1d10663389c..0503307df27 100644 --- a/src/main/java/org/jabref/logic/ai/AiService.java +++ b/src/main/java/org/jabref/logic/ai/AiService.java @@ -135,7 +135,11 @@ public SummariesService getSummariesService() { } public void openAiChat(StringProperty name, ObservableList chatHistory, BibDatabaseContext bibDatabaseContext, ObservableList entries) { - if (stateManager.getAiChatWindow().get().isEmpty()) { + Optional existingWindow = stateManager.getAiChatWindows().stream().filter(window -> window.getChatName().equals(name.get())).findFirst(); + + if (existingWindow.isPresent()) { + existingWindow.get().requestFocus(); + } else { AiChatWindow aiChatWindow = new AiChatWindow( this, dialogService, @@ -144,16 +148,15 @@ public void openAiChat(StringProperty name, ObservableList chatHist taskExecutor ); - aiChatWindow.setOnCloseRequest(event -> { - stateManager.getAiChatWindow().set(Optional.empty()); - }); + aiChatWindow.setOnCloseRequest(event -> + stateManager.getAiChatWindows().remove(aiChatWindow) + ); - stateManager.getAiChatWindow().set(Optional.of(aiChatWindow)); + stateManager.getAiChatWindows().add(aiChatWindow); dialogService.showCustomWindow(aiChatWindow); + aiChatWindow.setChat(name, chatHistory, bibDatabaseContext, entries); + aiChatWindow.requestFocus(); } - - stateManager.getAiChatWindow().get().get().setChat(name, chatHistory, bibDatabaseContext, entries); - stateManager.getAiChatWindow().get().get().requestFocus(); } @Override diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 2b066a08184..42b3d3999df 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2646,9 +2646,7 @@ An\ error\ occurred\ while\ opening\ the\ embeddings\ cache\ file.\ Embeddings\ An\ error\ occurred\ while\ opening\ the\ fully\ ingested\ documents\ cache\ file.\ Fully\ ingested\ documents\ will\ not\ be\ stored\ in\ the\ next\ session.=An error occurred while opening the fully ingested documents cache file. Fully ingested documents will not be stored in the next session. Invalid\ citation\ key\ for\ %0\ (%1)=Invalid citation key for %0 (%1) No\ citation\ key\ for\ %0=No citation key for %0 -No\ files\ attached\ to\ %0=No files attached to %0 Please\ attach\ at\ least\ one\ PDF\ file\ to\ enable\ summarization\ of\ PDF\ file(s).=Please attach at least one PDF file to enable summarization of PDF file(s). -The\ AI\ will\ not\ be\ able\ to\ find\ information\ in\ this\ entry=The AI will not be able to find information in this entry Unable\ to\ generate\ summary=Unable to generate summary Group\ %0=Group %0 AI\ chat\ with\ %0=AI chat with %0