diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java index b85b2437d8f..855a4ee9bad 100644 --- a/src/main/java/org/jabref/gui/JabRefGUI.java +++ b/src/main/java/org/jabref/gui/JabRefGUI.java @@ -24,7 +24,7 @@ import org.jabref.gui.remote.CLIMessageHandler; import org.jabref.gui.theme.ThemeManager; import org.jabref.gui.undo.CountingUndoManager; -import org.jabref.gui.util.DefaultDirectoryMonitor; +import org.jabref.gui.util.DirectoryMonitor; import org.jabref.gui.util.UiTaskExecutor; import org.jabref.logic.UiCommand; import org.jabref.logic.ai.AiService; @@ -41,7 +41,6 @@ import org.jabref.logic.util.WebViewStore; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.strings.StringUtil; -import org.jabref.model.util.DirectoryMonitor; import org.jabref.model.util.FileUpdateMonitor; import com.airhacks.afterburner.injection.Injector; @@ -135,7 +134,7 @@ public void start(Stage stage) { public void initialize() { WebViewStore.init(); - DirectoryMonitor directoryMonitor = new DefaultDirectoryMonitor(); + DirectoryMonitor directoryMonitor = new DirectoryMonitor(); Injector.setModelOrService(DirectoryMonitor.class, directoryMonitor); JabRefGUI.remoteListenerServerManager = new RemoteListenerServerManager(); @@ -263,7 +262,10 @@ private void openWindow() { } public void onShowing(WindowEvent event) { - Platform.runLater(() -> mainFrame.updateDividerPosition()); + Platform.runLater(() -> { + mainFrame.updateHorizontalDividerPosition(); + mainFrame.updateVerticalDividerPosition(); + }); // Open last edited databases if (uiCommands.stream().noneMatch(UiCommand.BlankWorkspace.class::isInstance) diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java index 646dd5c4923..1826625f9b3 100644 --- a/src/main/java/org/jabref/gui/LibraryTab.java +++ b/src/main/java/org/jabref/gui/LibraryTab.java @@ -7,7 +7,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Random; -import java.util.function.Supplier; import java.util.stream.Collectors; import javax.swing.undo.UndoManager; @@ -23,13 +22,11 @@ import javafx.beans.value.ObservableBooleanValue; import javafx.collections.ListChangeListener; import javafx.event.Event; -import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.control.Alert; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonType; import javafx.scene.control.ProgressIndicator; -import javafx.scene.control.SplitPane; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.Tooltip; @@ -45,7 +42,6 @@ import org.jabref.gui.autosaveandbackup.BackupManager; import org.jabref.gui.collab.DatabaseChangeMonitor; import org.jabref.gui.dialogs.AutosaveUiManager; -import org.jabref.gui.entryeditor.EntryEditor; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.externalfiles.ImportHandler; import org.jabref.gui.fieldeditors.LinkedFileViewModel; @@ -57,11 +53,10 @@ import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.undo.RedoAction; -import org.jabref.gui.undo.UndoAction; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.undo.UndoableInsertEntries; import org.jabref.gui.undo.UndoableRemoveEntries; +import org.jabref.gui.util.DirectoryMonitor; import org.jabref.gui.util.OptionalObjectProperty; import org.jabref.gui.util.UiTaskExecutor; import org.jabref.logic.ai.AiService; @@ -91,12 +86,9 @@ import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.event.EntriesEventSource; import org.jabref.model.entry.event.FieldChangedEvent; -import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.groups.GroupTreeNode; import org.jabref.model.search.query.SearchQuery; -import org.jabref.model.util.DirectoryMonitor; -import org.jabref.model.util.DirectoryMonitorManager; import org.jabref.model.util.FileUpdateMonitor; import com.airhacks.afterburner.injection.Injector; @@ -112,17 +104,13 @@ * Represents the ui area where the notifier pane, the library table and the entry editor are shown. */ public class LibraryTab extends Tab { - /** - * Defines the different modes that the tab can operate in - */ - private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR } - private static final Logger LOGGER = LoggerFactory.getLogger(LibraryTab.class); private final LibraryTabContainer tabContainer; private final CountingUndoManager undoManager; private final DialogService dialogService; private final GuiPreferences preferences; private final FileUpdateMonitor fileUpdateMonitor; + private final DirectoryMonitor directoryMonitor; private final StateManager stateManager; private final BibEntryTypesManager entryTypesManager; private final BooleanProperty changedProperty = new SimpleBooleanProperty(false); @@ -131,10 +119,7 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR } private BibDatabaseContext bibDatabaseContext; private MainTableDataModel tableModel; private FileAnnotationCache annotationCache; - private EntryEditor entryEditor; private MainTable mainTable; - private PanelMode mode = PanelMode.MAIN_TABLE; - private SplitPane splitPane; private DatabaseNotification databaseNotificationPane; // Indicates whether the tab is loading data using a dataloading task @@ -164,7 +149,6 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR } private final ClipBoardManager clipBoardManager; private final TaskExecutor taskExecutor; - private final DirectoryMonitorManager directoryMonitorManager; private ImportHandler importHandler; private IndexManager indexManager; @@ -184,6 +168,7 @@ private LibraryTab(BibDatabaseContext bibDatabaseContext, GuiPreferences preferences, StateManager stateManager, FileUpdateMonitor fileUpdateMonitor, + DirectoryMonitor directoryMonitor, BibEntryTypesManager entryTypesManager, CountingUndoManager undoManager, ClipBoardManager clipBoardManager, @@ -196,10 +181,10 @@ private LibraryTab(BibDatabaseContext bibDatabaseContext, this.preferences = Objects.requireNonNull(preferences); this.stateManager = Objects.requireNonNull(stateManager); this.fileUpdateMonitor = fileUpdateMonitor; + this.directoryMonitor = directoryMonitor; this.entryTypesManager = entryTypesManager; this.clipBoardManager = clipBoardManager; this.taskExecutor = taskExecutor; - this.directoryMonitorManager = new DirectoryMonitorManager(Injector.instantiateModelOrService(DirectoryMonitor.class)); this.aiService = aiService; initializeComponentsAndListeners(isDummyContext); @@ -225,7 +210,7 @@ private void initializeComponentsAndListeners(boolean isDummyContext) { bibDatabaseContext.getMetaData().registerListener(this); this.selectedGroupsProperty = new SimpleListProperty<>(stateManager.getSelectedGroups(bibDatabaseContext)); - this.tableModel = new MainTableDataModel(getBibDatabaseContext(), preferences, taskExecutor, getIndexManager(), selectedGroupsProperty(), searchQueryProperty(), resultSizeProperty()); + this.tableModel = new MainTableDataModel(getBibDatabaseContext(), preferences, taskExecutor, getIndexManager(), selectedGroupsProperty(), searchQueryProperty, resultSizeProperty()); new CitationStyleCache(bibDatabaseContext); annotationCache = new FileAnnotationCache(bibDatabaseContext, preferences.getFilePreferences()); @@ -242,7 +227,6 @@ private void initializeComponentsAndListeners(boolean isDummyContext) { setupAutoCompletion(); this.getDatabase().registerListener(new IndexUpdateListener()); - this.getDatabase().registerListener(new EntriesRemovedListener()); // ensure that at each addition of a new entry, the entry is added to the groups interface this.bibDatabaseContext.getDatabase().registerListener(new GroupTreeListener()); @@ -251,8 +235,6 @@ private void initializeComponentsAndListeners(boolean isDummyContext) { this.getDatabase().registerListener(new UpdateTimestampListener(preferences)); - this.entryEditor = createEntryEditor(); - aiService.setupDatabase(bibDatabaseContext); Platform.runLater(() -> { @@ -262,14 +244,6 @@ private void initializeComponentsAndListeners(boolean isDummyContext) { }); } - private EntryEditor createEntryEditor() { - Supplier tabSupplier = () -> this; - return new EntryEditor(this, - // Actions are recreated here since this avoids passing more parameters and the amount of additional memory consumption is neglegtable. - new UndoAction(tabSupplier, undoManager, dialogService, stateManager), - new RedoAction(tabSupplier, undoManager, dialogService, stateManager)); - } - private static void addChangedInformation(StringBuilder text, String fileName) { text.append("\n"); text.append(Localization.lang("Library '%0' has changed.", fileName)); @@ -478,14 +452,6 @@ public void registerUndoableChanges(List changes) { } } - public void editEntryAndFocusField(BibEntry entry, Field field) { - showAndEdit(entry); - Platform.runLater(() -> { - // Focus field and entry in main table (async to give entry editor time to load) - entryEditor.setFocusToField(field); - }); - } - private void createMainTable() { mainTable = new MainTable(tableModel, this, @@ -499,34 +465,21 @@ private void createMainTable() { entryTypesManager, taskExecutor, importHandler); + // Add the listener that binds selection to state manager (TODO: should be replaced by proper JavaFX binding as soon as table is implemented in JavaFX) // content binding between StateManager#getselectedEntries and mainTable#getSelectedEntries does not work here as it does not trigger the ActionHelper#needsEntriesSelected checker for the menubar mainTable.addSelectionListener(event -> { List entries = event.getList().stream().map(BibEntryTableViewModel::getEntry).toList(); stateManager.setSelectedEntries(entries); - if (!entries.isEmpty()) { - // Update entry editor and preview according to selected entries - entryEditor.setCurrentlyEditedEntry(entries.getFirst()); - } }); } public void setupMainPanel() { - splitPane = new SplitPane(); - splitPane.setOrientation(Orientation.VERTICAL); - createMainTable(); - splitPane.getItems().add(mainTable); - databaseNotificationPane = new DatabaseNotification(splitPane); + databaseNotificationPane = new DatabaseNotification(mainTable); setContent(databaseNotificationPane); - // Saves the divider position as soon as it changes - // We need to keep a reference to the subscription, otherwise the binding gets garbage collected - dividerPositionSubscription = EasyBind.valueAt(splitPane.getDividers(), 0) - .mapObservable(SplitPane.Divider::positionProperty) - .subscribeToValues(this::saveDividerLocation); - // Add changePane in case a file is present - otherwise just add the splitPane to the panel Optional file = bibDatabaseContext.getDatabasePath(); if (file.isPresent()) { @@ -562,37 +515,9 @@ public SuggestionProvider getAutoCompleter() { return searchAutoCompleter; } - public EntryEditor getEntryEditor() { - return entryEditor; - } - - /** - * Sets the entry editor as the bottom component in the split pane. If an entry editor already was shown, makes sure that the divider doesn't move. Updates the mode to {@link PanelMode#MAIN_TABLE_AND_ENTRY_EDITOR}. - * Then shows the given entry. - * - * Additionally, selects the entry in the main table - so that the selected entry in the main table always corresponds to the edited entry. - * - * @param entry The entry to edit. - */ public void showAndEdit(BibEntry entry) { this.clearAndSelect(entry); - if (!splitPane.getItems().contains(entryEditor)) { - splitPane.getItems().addLast(entryEditor); - mode = PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR; - splitPane.setDividerPositions(preferences.getEntryEditorPreferences().getDividerPosition()); - } - - // We use != instead of equals because of performance reasons - if (entry != showing) { - entryEditor.setCurrentlyEditedEntry(entry); - showing = entry; - } - entryEditor.requestFocus(); - } - - public void closeBottomPane() { - mode = PanelMode.MAIN_TABLE; - splitPane.getItems().remove(entryEditor); + stateManager.getEditorShowing().setValue(true); } /** @@ -610,25 +535,6 @@ public void selectNextEntry() { mainTable.getSelectionModel().clearAndSelect(mainTable.getSelectionModel().getSelectedIndex() + 1); } - /** - * This method is called from an EntryEditor when it should be closed. We relay to the selection listener, which takes care of the rest. - */ - public void entryEditorClosing() { - closeBottomPane(); - mainTable.requestFocus(); - } - - /** - * Closes the entry editor if it is showing any of the given entries. - */ - private void ensureNotShowingBottomPanel(List entriesToCheck) { - // This method is not able to close the bottom pane currently - - if ((mode == PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR) && (entriesToCheck.contains(entryEditor.getCurrentlyEditedEntry()))) { - closeBottomPane(); - } - } - /** * Put an asterisk behind the filename to indicate the database has changed. */ @@ -677,15 +583,6 @@ private boolean showDeleteConfirmationDialog(int numberOfEntries) { } } - /** - * Depending on whether a preview or an entry editor is showing, save the current divider location in the correct preference setting. - */ - private void saveDividerLocation(Number position) { - if (mode == PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR) { - preferences.getEntryEditorPreferences().setDividerPosition(position.doubleValue()); - } - } - public boolean requestClose() { if (bibDatabaseContext.getLocation() == DatabaseLocation.LOCAL) { if (isModified()) { @@ -781,11 +678,6 @@ private void onClosed(Event event) { } catch (RuntimeException e) { LOGGER.error("Problem when closing change monitor", e); } - try { - directoryMonitorManager.unregister(); - } catch (RuntimeException e) { - LOGGER.error("Problem when closing directory monitor", e); - } try { if (indexManager != null) { indexManager.close(); @@ -826,10 +718,6 @@ public BibDatabaseContext getBibDatabaseContext() { return this.bibDatabaseContext; } - public DirectoryMonitorManager getDirectoryMonitorManager() { - return directoryMonitorManager; - } - public boolean isSaving() { return saving; } @@ -890,6 +778,7 @@ public void insertEntries(final List entries) { importHandler.importCleanedEntries(entries); getUndoManager().addEdit(new UndoableInsertEntries(bibDatabaseContext.getDatabase(), entries)); markBaseChanged(); + stateManager.setSelectedEntries(entries); if (preferences.getEntryEditorPreferences().shouldOpenOnNewEntry()) { showAndEdit(entries.getFirst()); } else { @@ -1017,7 +906,6 @@ private int doDeleteEntry(StandardActions mode, List entries) { } } - ensureNotShowingBottomPanel(entries); markBaseChanged(); // prevent the main table from loosing focus @@ -1058,6 +946,7 @@ public static LibraryTab createLibraryTab(BackgroundTask dataLoadi StateManager stateManager, LibraryTabContainer tabContainer, FileUpdateMonitor fileUpdateMonitor, + DirectoryMonitor directoryMonitor, BibEntryTypesManager entryTypesManager, CountingUndoManager undoManager, ClipBoardManager clipBoardManager, @@ -1073,6 +962,7 @@ public static LibraryTab createLibraryTab(BackgroundTask dataLoadi preferences, stateManager, fileUpdateMonitor, + directoryMonitor, entryTypesManager, undoManager, clipBoardManager, @@ -1095,6 +985,7 @@ public static LibraryTab createLibraryTab(BibDatabaseContext databaseContext, GuiPreferences preferences, StateManager stateManager, FileUpdateMonitor fileUpdateMonitor, + DirectoryMonitor directoryMonitor, BibEntryTypesManager entryTypesManager, UndoManager undoManager, ClipBoardManager clipBoardManager, @@ -1109,6 +1000,7 @@ public static LibraryTab createLibraryTab(BibDatabaseContext databaseContext, preferences, stateManager, fileUpdateMonitor, + directoryMonitor, entryTypesManager, (CountingUndoManager) undoManager, clipBoardManager, @@ -1133,14 +1025,6 @@ public void listen(EntriesAddedEvent addedEntriesEvent) { } } - private class EntriesRemovedListener { - - @Subscribe - public void listen(EntriesRemovedEvent entriesRemovedEvent) { - ensureNotShowingBottomPanel(entriesRemovedEvent.getBibEntries()); - } - } - private class IndexUpdateListener { @Subscribe @@ -1188,8 +1072,4 @@ public String toString() { ", showing=" + showing + '}'; } - - public LibraryTabContainer getLibraryTabContainer() { - return tabContainer; - } } diff --git a/src/main/java/org/jabref/gui/LibraryTabContainer.java b/src/main/java/org/jabref/gui/LibraryTabContainer.java index 139653c87ca..b572d190e6d 100644 --- a/src/main/java/org/jabref/gui/LibraryTabContainer.java +++ b/src/main/java/org/jabref/gui/LibraryTabContainer.java @@ -2,6 +2,8 @@ import java.util.List; +import javafx.collections.ObservableList; + import org.jabref.model.database.BibDatabaseContext; import org.jspecify.annotations.NonNull; @@ -10,7 +12,7 @@ @NullMarked public interface LibraryTabContainer { - List getLibraryTabs(); + ObservableList getLibraryTabs(); @Nullable LibraryTab getCurrentLibraryTab(); diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index 435c018619d..fc98720dac5 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -8,10 +8,14 @@ import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; @@ -64,6 +68,7 @@ public class StateManager { private final ObservableMap indexManagers = FXCollections.observableHashMap(); private final OptionalObjectProperty activeSearchQuery = OptionalObjectProperty.empty(); private final OptionalObjectProperty activeGlobalSearchQuery = OptionalObjectProperty.empty(); + private final StringProperty searchQueryProperty = new SimpleStringProperty(); private final IntegerProperty searchResultSize = new SimpleIntegerProperty(0); private final IntegerProperty globalSearchResultSize = new SimpleIntegerProperty(0); private final OptionalObjectProperty focusOwner = OptionalObjectProperty.empty(); @@ -78,6 +83,7 @@ public class StateManager { private final ObjectProperty lastAutomaticFieldEditorEdit = new SimpleObjectProperty<>(); private final ObservableList searchHistory = FXCollections.observableArrayList(); private final List aiChatWindows = new ArrayList<>(); + private final BooleanProperty editorShowing = new SimpleBooleanProperty(false); public ObservableList getVisibleSidePaneComponents() { return visibleSidePanes; @@ -103,6 +109,10 @@ public OptionalObjectProperty activeSearchQuery(SearchType type) { return type == SearchType.NORMAL_SEARCH ? activeSearchQuery : activeGlobalSearchQuery; } + public StringProperty searchQueryProperty() { + return searchQueryProperty; + } + public IntegerProperty searchResultSize(SearchType type) { return type == SearchType.NORMAL_SEARCH ? searchResultSize : globalSearchResultSize; } @@ -231,4 +241,8 @@ public void clearSearchHistory() { public List getAiChatWindows() { return aiChatWindows; } + + public BooleanProperty getEditorShowing() { + return editorShowing; + } } diff --git a/src/main/java/org/jabref/gui/entryeditor/AiChatTab.java b/src/main/java/org/jabref/gui/entryeditor/AiChatTab.java index 29fb54f544c..1eafb3a5307 100644 --- a/src/main/java/org/jabref/gui/entryeditor/AiChatTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/AiChatTab.java @@ -11,6 +11,7 @@ import javafx.scene.control.Tooltip; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.ai.components.aichat.AiChatGuardedComponent; import org.jabref.gui.ai.components.privacynotice.PrivacyNoticeComponent; import org.jabref.gui.ai.components.util.errorstate.ErrorStateComponent; @@ -20,6 +21,7 @@ import org.jabref.logic.ai.AiService; import org.jabref.logic.ai.util.CitationKeyCheck; import org.jabref.logic.citationkeypattern.CitationKeyGenerator; +import org.jabref.logic.citationkeypattern.CitationKeyPatternPreferences; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.TaskExecutor; import org.jabref.logic.util.io.FileUtil; @@ -28,33 +30,30 @@ import org.jabref.model.entry.LinkedFile; public class AiChatTab extends EntryEditorTab { - private final BibDatabaseContext bibDatabaseContext; private final AiService aiService; private final DialogService dialogService; private final AiPreferences aiPreferences; private final ExternalApplicationsPreferences externalApplicationsPreferences; private final EntryEditorPreferences entryEditorPreferences; - private final CitationKeyGenerator citationKeyGenerator; + private final StateManager stateManager; private final TaskExecutor taskExecutor; + private final CitationKeyPatternPreferences citationKeyPatternPreferences; private Optional previousBibEntry = Optional.empty(); - public AiChatTab(BibDatabaseContext bibDatabaseContext, - AiService aiService, + public AiChatTab(AiService aiService, DialogService dialogService, GuiPreferences preferences, - TaskExecutor taskExecutor - ) { - this.bibDatabaseContext = bibDatabaseContext; - + StateManager stateManager, + TaskExecutor taskExecutor) { this.aiService = aiService; this.dialogService = dialogService; this.aiPreferences = preferences.getAiPreferences(); this.externalApplicationsPreferences = preferences.getExternalApplicationsPreferences(); this.entryEditorPreferences = preferences.getEntryEditorPreferences(); - - this.citationKeyGenerator = new CitationKeyGenerator(bibDatabaseContext, preferences.getCitationKeyPatternPreferences()); + this.citationKeyPatternPreferences = preferences.getCitationKeyPatternPreferences(); + this.stateManager = stateManager; this.taskExecutor = taskExecutor; @@ -74,6 +73,7 @@ public boolean shouldShow(BibEntry entry) { protected void bindToEntry(BibEntry entry) { previousBibEntry.ifPresent(previousBibEntry -> aiService.getChatHistoryService().closeChatHistoryForEntry(previousBibEntry)); previousBibEntry = Optional.of(entry); + BibDatabaseContext bibDatabaseContext = stateManager.getActiveDatabase().orElse(new BibDatabaseContext()); if (!aiPreferences.getEnableAi()) { showPrivacyNotice(entry); @@ -82,9 +82,9 @@ protected void bindToEntry(BibEntry entry) { } else if (entry.getFiles().stream().map(LinkedFile::getLink).map(Path::of).noneMatch(FileUtil::isPDFFile)) { showErrorNotPdfs(); } else if (!CitationKeyCheck.citationKeyIsPresentAndUnique(bibDatabaseContext, entry)) { - tryToGenerateCitationKeyThenBind(entry); + tryToGenerateCitationKeyThenBind(bibDatabaseContext, entry); } else { - bindToCorrectEntry(entry); + showChatPanel(bibDatabaseContext, entry); } } @@ -110,7 +110,8 @@ private void showErrorNoFiles() { ); } - private void tryToGenerateCitationKeyThenBind(BibEntry entry) { + private void tryToGenerateCitationKeyThenBind(BibDatabaseContext bibDatabaseContext, BibEntry entry) { + CitationKeyGenerator citationKeyGenerator = new CitationKeyGenerator(bibDatabaseContext, citationKeyPatternPreferences); if (citationKeyGenerator.generateAndSetKey(entry).isEmpty()) { setContent( new ErrorStateComponent( @@ -123,7 +124,7 @@ private void tryToGenerateCitationKeyThenBind(BibEntry entry) { } } - private void bindToCorrectEntry(BibEntry entry) { + private void showChatPanel(BibDatabaseContext bibDatabaseContext, BibEntry entry) { // We omit the localization here, because it is only a chat with one entry in the {@link EntryEditor}. // See documentation for {@link AiChatGuardedComponent#name}. StringProperty chatName = new SimpleStringProperty("entry " + entry.getCitationKey().orElse("")); diff --git a/src/main/java/org/jabref/gui/entryeditor/AiSummaryTab.java b/src/main/java/org/jabref/gui/entryeditor/AiSummaryTab.java index 6e77c34270f..1a701968128 100644 --- a/src/main/java/org/jabref/gui/entryeditor/AiSummaryTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/AiSummaryTab.java @@ -3,6 +3,7 @@ import javafx.scene.control.Tooltip; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.ai.components.summary.SummaryComponent; import org.jabref.gui.frame.ExternalApplicationsPreferences; import org.jabref.gui.preferences.GuiPreferences; @@ -14,23 +15,21 @@ import org.jabref.model.entry.BibEntry; public class AiSummaryTab extends EntryEditorTab { - private final BibDatabaseContext bibDatabaseContext; private final AiService aiService; private final DialogService dialogService; + private final StateManager stateManager; private final AiPreferences aiPreferences; private final ExternalApplicationsPreferences externalApplicationsPreferences; private final CitationKeyPatternPreferences citationKeyPatternPreferences; private final EntryEditorPreferences entryEditorPreferences; - public AiSummaryTab(BibDatabaseContext bibDatabaseContext, - AiService aiService, + public AiSummaryTab(AiService aiService, DialogService dialogService, - GuiPreferences preferences - ) { - this.bibDatabaseContext = bibDatabaseContext; - + StateManager stateManager, + GuiPreferences preferences) { this.aiService = aiService; this.dialogService = dialogService; + this.stateManager = stateManager; this.aiPreferences = preferences.getAiPreferences(); this.externalApplicationsPreferences = preferences.getExternalApplicationsPreferences(); @@ -51,6 +50,7 @@ public boolean shouldShow(BibEntry entry) { */ @Override protected void bindToEntry(BibEntry entry) { + BibDatabaseContext bibDatabaseContext = stateManager.getActiveDatabase().orElse(new BibDatabaseContext()); setContent(new SummaryComponent( bibDatabaseContext, entry, diff --git a/src/main/java/org/jabref/gui/entryeditor/CommentsTab.java b/src/main/java/org/jabref/gui/entryeditor/CommentsTab.java index e60891ce5e3..c1bbee669bc 100644 --- a/src/main/java/org/jabref/gui/entryeditor/CommentsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/CommentsTab.java @@ -16,7 +16,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; -import org.jabref.gui.autocompleter.SuggestionProviders; +import org.jabref.gui.StateManager; import org.jabref.gui.fieldeditors.FieldEditorFX; import org.jabref.gui.fieldeditors.FieldNameLabel; import org.jabref.gui.fieldeditors.MarkdownEditor; @@ -43,21 +43,19 @@ public class CommentsTab extends FieldsEditorTab { private boolean shouldShowHideButton; public CommentsTab(GuiPreferences preferences, - BibDatabaseContext databaseContext, - SuggestionProviders suggestionProviders, UndoManager undoManager, UndoAction undoAction, RedoAction redoAction, JournalAbbreviationRepository journalAbbreviationRepository, + StateManager stateManager, PreviewPanel previewPanel) { super(false, - databaseContext, - suggestionProviders, undoManager, undoAction, redoAction, preferences, journalAbbreviationRepository, + stateManager, previewPanel); this.defaultOwner = preferences.getOwnerPreferences().getDefaultOwner().toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", "-"); setText(Localization.lang("Comments")); @@ -118,8 +116,8 @@ private void setCompressedRowLayout() { } @Override - protected void setupPanel(BibEntry entry, boolean compressed) { - super.setupPanel(entry, compressed); + protected void setupPanel(BibDatabaseContext bibDatabaseContext, BibEntry entry, boolean compressed) { + super.setupPanel(bibDatabaseContext, entry, compressed); Optional fieldEditorForUserDefinedComment = editors.entrySet().stream().filter(f -> f.getKey().getName().contains(defaultOwner)).map(Map.Entry::getValue).findFirst(); @@ -147,7 +145,7 @@ protected void setupPanel(BibEntry entry, boolean compressed) { entry.clearField(userSpecificCommentField); shouldShowHideButton = false; - setupPanel(entry, false); + setupPanel(bibDatabaseContext, entry, false); }); gridPane.add(hideDefaultOwnerCommentButton, 1, gridPane.getRowCount(), 2, 1); setCompressedRowLayout(); @@ -156,7 +154,7 @@ protected void setupPanel(BibEntry entry, boolean compressed) { Button showDefaultOwnerCommentButton = new Button(Localization.lang("Show user-specific comments field")); showDefaultOwnerCommentButton.setOnAction(e -> { shouldShowHideButton = true; - setupPanel(entry, false); + setupPanel(bibDatabaseContext, entry, false); }); gridPane.add(showDefaultOwnerCommentButton, 1, gridPane.getRowCount(), 2, 1); setCompressedRowLayout(); diff --git a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java index cd4070c3a40..70b1655a991 100644 --- a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java @@ -9,7 +9,7 @@ import javafx.scene.control.Tooltip; -import org.jabref.gui.autocompleter.SuggestionProviders; +import org.jabref.gui.StateManager; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.preview.PreviewPanel; @@ -31,24 +31,22 @@ public class DeprecatedFieldsTab extends FieldsEditorTab { public static final String NAME = "Deprecated fields"; private final BibEntryTypesManager entryTypesManager; - public DeprecatedFieldsTab(BibDatabaseContext databaseContext, - SuggestionProviders suggestionProviders, - UndoManager undoManager, + public DeprecatedFieldsTab(UndoManager undoManager, UndoAction undoAction, RedoAction redoAction, GuiPreferences preferences, BibEntryTypesManager entryTypesManager, JournalAbbreviationRepository journalAbbreviationRepository, + StateManager stateManager, PreviewPanel previewPanel) { super( false, - databaseContext, - suggestionProviders, undoManager, undoAction, redoAction, preferences, journalAbbreviationRepository, + stateManager, previewPanel ); this.entryTypesManager = entryTypesManager; @@ -66,7 +64,8 @@ public DeprecatedFieldsTab(BibDatabaseContext databaseContext, @Override protected SequencedSet determineFieldsToShow(BibEntry entry) { - BibDatabaseMode mode = databaseContext.getMode(); + BibDatabaseMode mode = stateManager.getActiveDatabase().map(BibDatabaseContext::getMode) + .orElse(BibDatabaseMode.BIBLATEX); Optional entryType = entryTypesManager.enrich(entry.getType(), mode); if (entryType.isPresent()) { return entryType.get().getDeprecatedFields(mode).stream().filter(field -> entry.getField(field).isPresent()).collect(Collectors.toCollection(LinkedHashSet::new)); diff --git a/src/main/java/org/jabref/gui/entryeditor/DetailOptionalFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/DetailOptionalFieldsTab.java index 48fb2ef017f..5ea115fe41e 100644 --- a/src/main/java/org/jabref/gui/entryeditor/DetailOptionalFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/DetailOptionalFieldsTab.java @@ -2,40 +2,37 @@ import javax.swing.undo.UndoManager; -import org.jabref.gui.autocompleter.SuggestionProviders; +import org.jabref.gui.StateManager; import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.preview.PreviewPanel; import org.jabref.gui.undo.RedoAction; import org.jabref.gui.undo.UndoAction; import org.jabref.logic.journals.JournalAbbreviationRepository; import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntryTypesManager; public class DetailOptionalFieldsTab extends OptionalFieldsTabBase { public static final String NAME = "Optional fields 2"; - public DetailOptionalFieldsTab(BibDatabaseContext databaseContext, - SuggestionProviders suggestionProviders, - UndoManager undoManager, + public DetailOptionalFieldsTab(UndoManager undoManager, UndoAction undoAction, RedoAction redoAction, GuiPreferences preferences, BibEntryTypesManager entryTypesManager, JournalAbbreviationRepository journalAbbreviationRepository, + StateManager stateManager, PreviewPanel previewPanel) { super( Localization.lang("Optional fields 2"), false, - databaseContext, - suggestionProviders, undoManager, undoAction, redoAction, preferences, entryTypesManager, journalAbbreviationRepository, + stateManager, previewPanel ); } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index f36a42aeef0..7cb7730b674 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -2,6 +2,7 @@ import java.io.File; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -11,9 +12,11 @@ import java.util.Optional; import java.util.Set; import java.util.SortedSet; +import java.util.function.Supplier; import java.util.stream.Collectors; import javafx.application.Platform; +import javafx.beans.InvalidationListener; import javafx.fxml.FXML; import javafx.geometry.Side; import javafx.scene.control.Button; @@ -43,11 +46,13 @@ import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.preferences.GuiPreferences; +import org.jabref.gui.preview.PreviewControls; import org.jabref.gui.preview.PreviewPanel; import org.jabref.gui.theme.ThemeManager; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.RedoAction; import org.jabref.gui.undo.UndoAction; +import org.jabref.gui.util.DirectoryMonitor; import org.jabref.gui.util.DragDrop; import org.jabref.gui.util.UiTaskExecutor; import org.jabref.logic.ai.AiService; @@ -59,12 +64,10 @@ import org.jabref.logic.journals.JournalAbbreviationRepository; import org.jabref.logic.util.BuildInfo; import org.jabref.logic.util.TaskExecutor; -import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.entry.EntryConverter; import org.jabref.model.entry.field.Field; -import org.jabref.model.util.DirectoryMonitorManager; import org.jabref.model.util.FileUpdateMonitor; import com.airhacks.afterburner.views.ViewLoader; @@ -72,8 +75,6 @@ import com.tobiasdiez.easybind.Subscription; import jakarta.inject.Inject; import org.jspecify.annotations.NonNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * GUI component that allows editing of the fields of a BibEntry (i.e. the one that shows up, when you double click on @@ -86,16 +87,10 @@ *

* The editors for fields are created via {@link org.jabref.gui.fieldeditors.FieldEditors}. */ -public class EntryEditor extends BorderPane { - - private static final Logger LOGGER = LoggerFactory.getLogger(EntryEditor.class); - - private final LibraryTab libraryTab; - private final BibDatabaseContext databaseContext; - private final EntryEditorPreferences entryEditorPreferences; +public class EntryEditor extends BorderPane implements PreviewControls { + private final Supplier tabSupplier; private final ExternalFilesEntryLinker fileLinker; private final PreviewPanel previewPanel; - private final DirectoryMonitorManager directoryMonitorManager; private final UndoAction undoAction; private final RedoAction redoAction; @@ -118,18 +113,17 @@ public class EntryEditor extends BorderPane { @Inject private StateManager stateManager; @Inject private ThemeManager themeManager; @Inject private FileUpdateMonitor fileMonitor; + @Inject private DirectoryMonitor directoryMonitor; @Inject private CountingUndoManager undoManager; @Inject private BibEntryTypesManager bibEntryTypesManager; @Inject private KeyBindingRepository keyBindingRepository; @Inject private JournalAbbreviationRepository journalAbbreviationRepository; @Inject private AiService aiService; - private final List allPossibleTabs; + private final List allPossibleTabs = new ArrayList<>(); - public EntryEditor(LibraryTab libraryTab, UndoAction undoAction, RedoAction redoAction) { - this.libraryTab = libraryTab; - this.databaseContext = libraryTab.getBibDatabaseContext(); - this.directoryMonitorManager = libraryTab.getDirectoryMonitorManager(); + public EntryEditor(Supplier tabSupplier, UndoAction undoAction, RedoAction redoAction) { + this.tabSupplier = tabSupplier; this.undoAction = undoAction; this.redoAction = redoAction; @@ -137,21 +131,34 @@ public EntryEditor(LibraryTab libraryTab, UndoAction undoAction, RedoAction redo .root(this) .load(); - this.entryEditorPreferences = preferences.getEntryEditorPreferences(); - this.fileLinker = new ExternalFilesEntryLinker(preferences.getExternalApplicationsPreferences(), preferences.getFilePreferences(), dialogService, stateManager); + this.fileLinker = new ExternalFilesEntryLinker( + preferences.getExternalApplicationsPreferences(), + preferences.getFilePreferences(), + dialogService, + stateManager); + this.previewPanel = new PreviewPanel( dialogService, preferences.getKeyBindingRepository(), preferences, themeManager, taskExecutor, - stateManager, - libraryTab.searchQueryProperty()); - this.previewPanel.setDatabase(databaseContext); + stateManager); setupKeyBindings(); - this.allPossibleTabs = createTabs(); + EasyBind.subscribe(stateManager.activeTabProperty(), tab -> { + if (tab.isPresent()) { + tabbed.getTabs().clear(); + + this.allPossibleTabs.clear(); + this.allPossibleTabs.addAll(createTabs(tab.get())); + + adaptVisibleTabs(); + } else { + this.allPossibleTabs.clear(); + } + }); setupDragAndDrop(); @@ -162,6 +169,15 @@ public EntryEditor(LibraryTab libraryTab, UndoAction undoAction, RedoAction redo } }); + stateManager.getSelectedEntries().addListener((InvalidationListener) c -> { + if (stateManager.getSelectedEntries().isEmpty()) { + setCurrentlyEditedEntry(new BibEntry()); + } else { + setCurrentlyEditedEntry(stateManager.getSelectedEntries().getFirst()); + } + } + ); + EasyBind.listen(preferences.getPreviewPreferences().showPreviewAsExtraTabProperty(), (obs, oldValue, newValue) -> { if (currentlyEditedEntry != null) { @@ -222,11 +238,11 @@ private void setupKeyBindings() { event.consume(); break; case ENTRY_EDITOR_NEXT_ENTRY: - libraryTab.selectNextEntry(); + tabSupplier.get().selectNextEntry(); event.consume(); break; case ENTRY_EDITOR_PREVIOUS_ENTRY: - libraryTab.selectPreviousEntry(); + tabSupplier.get().selectPreviousEntry(); event.consume(); break; case HELP: @@ -250,66 +266,65 @@ private void setupKeyBindings() { } @FXML - public void close() { - libraryTab.entryEditorClosing(); + private void close() { + stateManager.getEditorShowing().set(false); } @FXML private void deleteEntry() { - libraryTab.deleteEntry(currentlyEditedEntry); + tabSupplier.get().deleteEntry(currentlyEditedEntry); } @FXML - void generateCiteKeyButton() { - GenerateCitationKeySingleAction action = new GenerateCitationKeySingleAction(getCurrentlyEditedEntry(), databaseContext, + private void generateCiteKeyButton() { + GenerateCitationKeySingleAction action = new GenerateCitationKeySingleAction(getCurrentlyEditedEntry(), tabSupplier.get().getBibDatabaseContext(), dialogService, preferences, undoManager); action.execute(); } @FXML - void generateCleanupButton() { + private void generateCleanupButton() { CleanupSingleAction action = new CleanupSingleAction(getCurrentlyEditedEntry(), preferences, dialogService, stateManager, undoManager); action.execute(); } @FXML private void navigateToPreviousEntry() { - libraryTab.selectPreviousEntry(); + tabSupplier.get().selectPreviousEntry(); } @FXML private void navigateToNextEntry() { - libraryTab.selectNextEntry(); + tabSupplier.get().selectNextEntry(); } - private List createTabs() { + private List createTabs(LibraryTab libraryTab) { List tabs = new LinkedList<>(); - tabs.add(new PreviewTab(databaseContext, preferences, previewPanel)); + tabs.add(new PreviewTab(preferences, stateManager, previewPanel)); // Required, optional (important+detail), deprecated, and "other" fields - tabs.add(new RequiredFieldsTab(databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, previewPanel)); - tabs.add(new ImportantOptionalFieldsTab(databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, previewPanel)); - tabs.add(new DetailOptionalFieldsTab(databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, previewPanel)); - tabs.add(new DeprecatedFieldsTab(databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, previewPanel)); - tabs.add(new OtherFieldsTab(databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, previewPanel)); + tabs.add(new RequiredFieldsTab(undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, stateManager, previewPanel)); + tabs.add(new ImportantOptionalFieldsTab(undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, stateManager, previewPanel)); + tabs.add(new DetailOptionalFieldsTab(undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, stateManager, previewPanel)); + tabs.add(new DeprecatedFieldsTab(undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, stateManager, previewPanel)); + tabs.add(new OtherFieldsTab(undoManager, undoAction, redoAction, preferences, bibEntryTypesManager, journalAbbreviationRepository, stateManager, previewPanel)); // Comment Tab: Tab for general and user-specific comments - tabs.add(new CommentsTab(preferences, databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, journalAbbreviationRepository, previewPanel)); + tabs.add(new CommentsTab(preferences, undoManager, undoAction, redoAction, journalAbbreviationRepository, stateManager, previewPanel)); + // ToDo: Needs to be recreated on preferences change Map> entryEditorTabList = getAdditionalUserConfiguredTabs(); for (Map.Entry> tab : entryEditorTabList.entrySet()) { - tabs.add(new UserDefinedFieldsTab(tab.getKey(), tab.getValue(), databaseContext, libraryTab.getSuggestionProviders(), undoManager, undoAction, redoAction, preferences, journalAbbreviationRepository, previewPanel)); + tabs.add(new UserDefinedFieldsTab(tab.getKey(), tab.getValue(), undoManager, undoAction, redoAction, preferences, journalAbbreviationRepository, stateManager, previewPanel)); } tabs.add(new MathSciNetTab()); - tabs.add(new FileAnnotationTab(libraryTab.getAnnotationCache())); + tabs.add(new FileAnnotationTab(stateManager)); tabs.add(new SciteTab(preferences, taskExecutor, dialogService)); - tabs.add(new CitationRelationsTab(dialogService, databaseContext, - undoManager, stateManager, fileMonitor, preferences, libraryTab, taskExecutor, bibEntryTypesManager)); - tabs.add(new RelatedArticlesTab(buildInfo, databaseContext, preferences, dialogService, taskExecutor)); + tabs.add(new CitationRelationsTab(dialogService, undoManager, stateManager, fileMonitor, preferences, taskExecutor, bibEntryTypesManager)); + tabs.add(new RelatedArticlesTab(buildInfo, preferences, dialogService, stateManager, taskExecutor)); sourceTab = new SourceTab( - databaseContext, undoManager, preferences.getFieldPreferences(), preferences.getImportFormatPreferences(), @@ -317,12 +332,12 @@ private List createTabs() { dialogService, bibEntryTypesManager, keyBindingRepository, - libraryTab.searchQueryProperty()); + stateManager); tabs.add(sourceTab); - tabs.add(new LatexCitationsTab(databaseContext, preferences, dialogService, directoryMonitorManager)); - tabs.add(new FulltextSearchResultsTab(stateManager, preferences, dialogService, databaseContext, taskExecutor, libraryTab.searchQueryProperty())); - tabs.add(new AiSummaryTab(libraryTab.getBibDatabaseContext(), aiService, dialogService, preferences)); - tabs.add(new AiChatTab(libraryTab.getBibDatabaseContext(), aiService, dialogService, preferences, taskExecutor)); + tabs.add(new LatexCitationsTab(preferences, dialogService, stateManager, directoryMonitor)); + tabs.add(new FulltextSearchResultsTab(stateManager, preferences, dialogService, taskExecutor)); + tabs.add(new AiSummaryTab(aiService, dialogService, stateManager, preferences)); + tabs.add(new AiChatTab(aiService, dialogService, preferences, stateManager, taskExecutor)); return tabs; } @@ -335,7 +350,7 @@ private List createTabs() { * @return Map of tab names and the fields to show in them. */ private Map> getAdditionalUserConfiguredTabs() { - Map> entryEditorTabList = new HashMap<>(entryEditorPreferences.getEntryEditorTabs()); + Map> entryEditorTabList = new HashMap<>(preferences.getEntryEditorPreferences().getEntryEditorTabs()); // Same order as in org.jabref.gui.entryeditor.EntryEditor.createTabs before the call of getAdditionalUserConfiguredTabs entryEditorTabList.remove(PreviewTab.NAME); @@ -368,6 +383,11 @@ private void adaptVisibleTabs() { // the tabs give an ugly animation the looks like all tabs are shifting in from the right. In other words: // This hack is required since tabbed.getTabs().setAll(visibleTabs) changes the order of the tabs in the editor + if (currentlyEditedEntry == null) { + tabbed.getTabs().clear(); + return; + } + // First, remove tabs that we do not want to show List toBeRemoved = allPossibleTabs.stream().filter(tab -> !tab.shouldShow(currentlyEditedEntry)).toList(); tabbed.getTabs().removeAll(toBeRemoved); @@ -404,14 +424,17 @@ public void setCurrentlyEditedEntry(@NonNull BibEntry currentlyEditedEntry) { // Remove subscription for old entry if existing typeSubscription.unsubscribe(); } - typeSubscription = EasyBind.subscribe(this.currentlyEditedEntry.typeProperty(), type -> { - typeLabel.setText(new TypedBibEntry(currentlyEditedEntry, databaseContext.getMode()).getTypeForDisplay()); - adaptVisibleTabs(); - setupToolBar(); - getSelectedTab().notifyAboutFocus(currentlyEditedEntry); - }); - if (entryEditorPreferences.showSourceTabByDefault()) { + if (!currentlyEditedEntry.isEmpty()) { + typeSubscription = EasyBind.subscribe(this.currentlyEditedEntry.typeProperty(), type -> { + typeLabel.setText(new TypedBibEntry(currentlyEditedEntry, tabSupplier.get().getBibDatabaseContext().getMode()).getTypeForDisplay()); + adaptVisibleTabs(); + setupToolBar(); + getSelectedTab().notifyAboutFocus(currentlyEditedEntry); + }); + } + + if (preferences.getEntryEditorPreferences().showSourceTabByDefault()) { tabbed.getSelectionModel().select(sourceTab); } } @@ -422,11 +445,11 @@ private EntryEditorTab getSelectedTab() { private void setupToolBar() { // Update type label - TypedBibEntry typedEntry = new TypedBibEntry(currentlyEditedEntry, databaseContext.getMode()); + TypedBibEntry typedEntry = new TypedBibEntry(currentlyEditedEntry, tabSupplier.get().getBibDatabaseContext().getMode()); typeLabel.setText(typedEntry.getTypeForDisplay()); // Add type change menu - ContextMenu typeMenu = new ChangeEntryTypeMenu(Collections.singletonList(currentlyEditedEntry), databaseContext, undoManager, bibEntryTypesManager).asContextMenu(); + ContextMenu typeMenu = new ChangeEntryTypeMenu(Collections.singletonList(currentlyEditedEntry), tabSupplier.get().getBibDatabaseContext(), undoManager, bibEntryTypesManager).asContextMenu(); typeLabel.setOnMouseClicked(event -> typeMenu.show(typeLabel, Side.RIGHT, 0, 0)); typeChangeButton.setOnMouseClicked(event -> typeMenu.show(typeChangeButton, Side.RIGHT, 0, 0)); @@ -436,7 +459,7 @@ private void setupToolBar() { preferences.getImporterPreferences(), preferences.getImportFormatPreferences(), preferences.getFilePreferences(), - databaseContext); + tabSupplier.get().getBibDatabaseContext()); for (EntryBasedFetcher fetcher : entryBasedFetchers) { MenuItem fetcherMenuItem = new MenuItem(fetcher.getName()); if (fetcher instanceof PdfMergeMetadataImporter.EntryBasedFetcherWrapper) { @@ -447,7 +470,7 @@ private void setupToolBar() { new PdfMergeMetadataImporter.EntryBasedFetcherWrapper( preferences.getImportFormatPreferences(), preferences.getFilePreferences(), - databaseContext); + tabSupplier.get().getBibDatabaseContext()); fetchAndMerge(pdfMergeMetadataImporter); }); } else { @@ -460,7 +483,7 @@ private void setupToolBar() { } private void fetchAndMerge(EntryBasedFetcher fetcher) { - new FetchAndMergeEntry(libraryTab.getBibDatabaseContext(), taskExecutor, preferences, dialogService, undoManager).fetchAndMerge(currentlyEditedEntry, fetcher); + new FetchAndMergeEntry(tabSupplier.get().getBibDatabaseContext(), taskExecutor, preferences, dialogService, undoManager).fetchAndMerge(currentlyEditedEntry, fetcher); } public void setFocusToField(Field field) { @@ -488,10 +511,12 @@ public void setFocusToField(Field field) { }); } + @Override public void nextPreviewStyle() { this.previewPanel.nextPreviewStyle(); } + @Override public void previousPreviewStyle() { this.previewPanel.previousPreviewStyle(); } diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java index 39cfdf8ff89..fb1bb8dfbf7 100644 --- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java @@ -24,6 +24,8 @@ import javafx.scene.layout.Region; import javafx.scene.layout.RowConstraints; +import org.jabref.gui.LibraryTab; +import org.jabref.gui.StateManager; import org.jabref.gui.autocompleter.SuggestionProviders; import org.jabref.gui.fieldeditors.FieldEditorFX; import org.jabref.gui.fieldeditors.FieldEditors; @@ -52,7 +54,6 @@ abstract class FieldsEditorTab extends TabWithPreviewPanel { protected final Map editors = new LinkedHashMap<>(); protected GridPane gridPane; private final boolean isCompressed; - private final SuggestionProviders suggestionProviders; private final UndoAction undoAction; private final RedoAction redoAction; private final GuiPreferences preferences; @@ -65,17 +66,15 @@ abstract class FieldsEditorTab extends TabWithPreviewPanel { private Subscription dividerPositionSubscription; public FieldsEditorTab(boolean compressed, - BibDatabaseContext databaseContext, - SuggestionProviders suggestionProviders, UndoManager undoManager, UndoAction undoAction, RedoAction redoAction, GuiPreferences preferences, JournalAbbreviationRepository journalAbbreviationRepository, + StateManager stateManager, PreviewPanel previewPanel) { - super(databaseContext, previewPanel); + super(stateManager, previewPanel); this.isCompressed = compressed; - this.suggestionProviders = Objects.requireNonNull(suggestionProviders); this.undoManager = Objects.requireNonNull(undoManager); this.undoAction = undoAction; this.redoAction = redoAction; @@ -91,7 +90,7 @@ private static void addColumn(GridPane gridPane, int columnIndex, Stream gridPane.addColumn(columnIndex, nodes.toArray(Node[]::new)); } - protected void setupPanel(BibEntry entry, boolean compressed) { + protected void setupPanel(BibDatabaseContext bibDatabaseContext, BibEntry entry, boolean compressed) { // The preferences might be not initialized in tests -> return immediately // TODO: Replace this ugly workaround by proper injection propagation if (preferences == null) { @@ -107,7 +106,7 @@ protected void setupPanel(BibEntry entry, boolean compressed) { List