Repository: JabRef/jabref
Pull request #12633: Improve TagsField of keywords
Author: login: Lin-Hi
Created: 2025-03-06T21:09:47Z | Merged: 2025-03-07T14:28:54Z

## Changes

1. On paste: If it is possible to add this keyword, directly add it without requiring the user to press Enter

    | Before | After |
    | :---: | :---: |
    | <img width="280" alt="paste-before" src="https://github.com/user-attachments/assets/a3944273-44ea-4aa5-955e-40a1034c24d6" /> | <img width="280" alt="paste-after" src="https://github.com/user-attachments/assets/5a4339da-a7f9-4682-a62d-b54de72acb74" />|

2. Double click on keyword: remove it and enter edit mode.
    | Before | After |
    | :---: | :---: |
    |<img width="280" alt="doubleClick-before" src="https://github.com/user-attachments/assets/778ac6f5-48e1-489b-9058-4ca49a6638e0" />|<img width="280" alt="doubleClick-after" src="https://github.com/user-attachments/assets/2ccde94e-7e62-475e-812c-dae26b7cf424" />|

3. Reorder keywords by drag and drop
    | Before | After |
    | :---: | :---: |
    |<img width="280" alt="drag-before" src="https://github.com/user-attachments/assets/fb6f9792-51b5-4533-a8d0-1b0438ab9c1e" />|<img width="280" alt="drag-after" src="https://github.com/user-attachments/assets/85c94dab-bb5a-41b6-9175-4e2d9224dd83" />|

4. Alphabetic ordering of keywords. In case the list is already alphabetically ordered, add the new keyword in alphabetical order. Otherwise, add it to the end
    | Before | After |
    | :---: | :---: |
    |<img width="280" alt="order-before" src="https://github.com/user-attachments/assets/040bb0f6-bdc7-4d5b-baed-a2ce2d59e38d" />|<img width="280" alt="order-after" src="https://github.com/user-attachments/assets/9dad7f0f-255d-4415-84bf-0b837ae6530b" />|

## Notes

This pull request is a new version of https://github.com/JabRef/jabref/pull/12632 but solve checkstyle errors and branch name. The old pull request is closed and ignored.

Closes #10984

## Mandatory Checks

- [x] I own the copyright of the code submitted and I licence it under the [MIT license](https://github.com/JabRef/jabref/blob/main/LICENSE)
- [x] Change in `CHANGELOG.md` described in a way that is understandable for the average user (if change is visible to the user)
- [ ] Tests created for changes (if applicable)
- [x] Manually tested changed features in running JabRef (always required)
- [x] Screenshots added in PR description (for UI changes)
- [x] [Checked developer's documentation](https://devdocs.jabref.org/): Is the information available and up to date? If not, I outlined it in this pull request.
- [x] [Checked documentation](https://docs.jabref.org/): Is the information available and up to date? If not, I created an issue at <https://github.com/JabRef/user-documentation/issues> or, even better, I submitted a pull request to the documentation repository.


Linked issue #10984: Improve TagsField of keywords
This is a follow-up of https://github.com/JabRef/jabref/pull/10910

For things are left open:

1. On paste: If it is possible to add this keyword, directly add it without requiring the user to press Enter
2. Double click on keyword: remove it and enter edit mode. Example:
   double click on "Where" 
![image](https://github.com/JabRef/jabref/assets/1366654/a80fef49-d3a8-4085-9348-64c4a5528b5b)
    leads to 
    ![image](https://github.com/JabRef/jabref/assets/1366654/ad12b255-31af-4d32-b406-f42b2c4912c0)
3. Reorder keywords by drag and drop
4. Alphabetic ordering of keywords. In case the list is already alphabetically ordered, add the new keyword in alphabetical order. Otherwise, add it to the end

If something does not work, it should be explained why it is not possible.
Linked issue comments: user: login: inteqam
created_at: 2024-03-05T17:57:46Z
body: Hi, i want to work on this issue can u give me prerequisite for it or resources that can guide me solving this issue ?
author_association: NONE
user: login: github-actions[bot]
created_at: 2024-03-05T20:22:35Z
body: As a general advice for newcomers: check out [Contributing](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md) for a start. Also, [guidelines for setting up a local workspace](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) is worth having a look at.

Feel free to ask here at GitHub, if you have any issue related questions. If you have questions about how to setup your workspace use JabRef's [Gitter](https://gitter.im/JabRef/jabref) chat. Try to open a (draft) pull-request early on, so that people can see you are working on the issue and so that they can see the direction the pull request is heading towards. This way, you will likely receive valuable feedback.
author_association: CONTRIBUTOR
user: login: nine03
created_at: 2024-03-12T08:42:59Z
body: Hi, i want to work on this issue.
Can you assign me this issue?
author_association: NONE
user: login: ThiloteE
created_at: 2024-03-12T08:49:52Z
body: @inteqam depends on you. Do you intend to open a pull-request? Otherwise I will assign nine03.
author_association: MEMBER
user: login: inteqam
created_at: 2024-03-12T10:01:23Z
body: yes , I am working on this issue 
author_association: NONE
user: login: ThiloteE
created_at: 2024-03-12T12:11:30Z
body: @nine03 please have a look at other [good first issues](https://github.com/orgs/JabRef/projects/5/views/1) or [candidates for university projects](https://github.com/orgs/JabRef/projects/3/views/3) that are "free to take". Obviously, you can also look at our other project boards, but those are not curated for students, so might be more tricky.
author_association: MEMBER
user: login: koppor
created_at: 2024-04-08T23:00:13Z
body: @inteqam Any update?
author_association: MEMBER
user: login: MrunalKashid02
created_at: 2024-09-24T13:39:33Z
body: Hi, Can I take this issue 

author_association: NONE
user: login: koppor
created_at: 2024-09-25T12:48:39Z
body: 	@MrunalKashid02 Sure! Go ahead!
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2024-09-25T13:13:09Z
body: Welcome to the vibrant world of open-source development with JabRef!

Newcomers, we're excited to have you on board. Start by exploring our [Contributing](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md) guidelines, and don't forget to check out our [workspace setup guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) to get started smoothly.

In case you encounter failing tests during development, please check our [developer FAQs](https://devdocs.jabref.org/code-howtos/faq.html)!

Having any questions or issues? Feel free to ask here on GitHub. Need help setting up your local workspace? Join the conversation on [JabRef's Gitter chat](https://gitter.im/JabRef/jabref). And don't hesitate to open a (draft) pull request early on to show the direction it is heading towards. This way, you will receive valuable feedback.

Happy coding! 🚀
author_association: CONTRIBUTOR
user: login: MrunalKashid02
created_at: 2024-09-29T10:53:21Z
body: I am done with 1-3 task but still remain with 4 task.  for 4 task Keywords should be alphabetically arranged as soon as Entered right ?
author_association: NONE
user: login: MrunalKashid02
created_at: 2024-09-29T14:24:36Z
body: can i make draft PR ?
author_association: NONE
user: login: Siedlerchr
created_at: 2024-09-29T14:34:02Z
body: @MrunalKashid02  Yes it's always good idea to make a draft pr
author_association: MEMBER
user: login: MrunalKashid02
created_at: 2024-09-29T19:03:32Z
body: I made draft  PR #11853. but dont know but their something wrong like This branch has conflict that must be resolved and checks also not passed why is it ? should i made a mistake ?

author_association: NONE
user: login: subhramit
created_at: 2024-10-01T01:27:12Z
body: > I made draft PR #11853. but dont know but their something wrong like This branch has conflict that must be resolved and checks also not passed why is it ? should i made a mistake ?

Read about resolution of merge conflicts. Maybe watch a short video on youtube or so. It's basically when there are conflicting changes to the same file, so they need to be resolved such that a final working version of a file can be generated.
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2024-11-15T17:01:56Z
body: 👋 Hey @DanielS01ss, it looks like you're interested in working on this issue! 🎉

If you'd like to take on this issue, please use the command `/assign-me` to assign yourself.
author_association: CONTRIBUTOR
user: login: DanielS01ss
created_at: 2024-11-15T17:03:15Z
body: /assign-me
author_association: NONE
user: login: github-actions[bot]
created_at: 2024-11-15T17:03:26Z
body: 👋 Hey @DanielS01ss, thank you for your interest in this issue! 🎉

We're excited to have you on board. Start by exploring our [Contributing](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md) guidelines, and don't forget to check out our [workspace setup guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) to get started smoothly.

In case you encounter failing tests during development, please check our [developer FAQs](https://devdocs.jabref.org/code-howtos/faq.html)!

Having any questions or issues? Feel free to ask here on GitHub. Need help setting up your local workspace? Join the conversation on [JabRef's Gitter chat](https://gitter.im/JabRef/jabref). And don't hesitate to open a (draft) pull request early on to show the direction it is heading towards. This way, you will receive valuable feedback.

Happy coding! 🚀

⏳ Please note, you will be automatically unassigned if the issue isn't closed within **30 days** (by **15 December 2024**). A maintainer can also add the "**📌 Pinned**"" label to prevent automatic unassignment.
author_association: CONTRIBUTOR
user: login: Lin-Hi
created_at: 2025-03-02T19:56:38Z
body: Hi, I'm a student from KTH Royal Institute of Technology taking DD2480 Software Engineering Foundamentals course now. Our assignment requires us to pick an issue with no asignee or with asignee but not been done yet. I saw this issue and interested in it. Can @koppor or other administer tell me whether this issue has already been solved? Thanks!
author_association: CONTRIBUTOR
user: login: subhramit
created_at: 2025-03-03T07:12:51Z
body: @Lin-Hi Hey, welcome to JabRef! Since there had been no progress from the past  asignee, you are welcome to take this.
author_association: MEMBER
user: login: subhramit
created_at: 2025-03-03T07:13:47Z
body: /assign @Lin-Hi
author_association: MEMBER
user: login: github-actions[bot]
created_at: 2025-03-03T07:14:01Z
body: 👋 Hey @Lin-Hi, thank you for your interest in this issue! 🎉

We're excited to have you on board. Start by exploring our [Contributing](https://github.com/JabRef/jabref/blob/main/CONTRIBUTING.md) guidelines, and don't forget to check out our [workspace setup guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace) to get started smoothly.

In case you encounter failing tests during development, please check our [developer FAQs](https://devdocs.jabref.org/code-howtos/faq.html)!

Having any questions or issues? Feel free to ask here on GitHub. Need help setting up your local workspace? Join the conversation on [JabRef's Gitter chat](https://gitter.im/JabRef/jabref). And don't hesitate to open a (draft) pull request early on to show the direction it is heading towards. This way, you will receive valuable feedback.

Happy coding! 🚀

⏳ Please note, you will be automatically unassigned if the issue isn't closed within **45 days** (by **17 April 2025**). A maintainer can also add the "**📌 Pinned**"" label to prevent automatic unassignment.
author_association: CONTRIBUTOR
user: login: Lin-Hi
created_at: 2025-03-06T20:42:29Z
body: Hi, our group finish the work and have no error in checkstyle. Our pull requrest is: https://github.com/JabRef/jabref/pull/12632
author_association: CONTRIBUTOR
user: login: subhramit
created_at: 2025-03-06T20:48:28Z
body: > Hi, our group finish the work and have no error in checkstyle. Our pull requrest is: [#12632](https://github.com/JabRef/jabref/pull/12632)

Hi Lin-Hi, please look at the failing tests. Once they are fixed, we will review your pull request.
author_association: MEMBER
user: login: Lin-Hi
created_at: 2025-03-06T21:29:12Z
body: Hi, we solve the failing tests. Because we use the wrong branch name, we have to open a new pull request https://github.com/JabRef/jabref/pull/12633, I've commented on old pull request for the new request and closed [the old one](https://github.com/JabRef/jabref/pull/12632). Please tell me if something still needs to be fixed. : )
author_association: CONTRIBUTOR
user: login: Lin-Hi
created_at: 2025-03-07T09:41:39Z
body: Hi, I change code according to your reviews. Contact if there's more problem.
author_association: CONTRIBUTOR

Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e54e07046cb..ad8b2e12660 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
 - We added a new dialog for bibliography consistency check. [#11950](https://github.com/JabRef/jabref/issues/11950)
 - We added a feature for copying entries to libraries, available via the context menu, with an option to include cross-references. [#12374](https://github.com/JabRef/jabref/pull/12374)
 - We added an integrity check if a URL appears in a title. [#12354](https://github.com/JabRef/jabref/issues/12354)
+- We added support for reordering keywords via drag and drop, automatic alphabetical ordering, and improved pasting and editing functionalities in the keyword editor. [#10984](https://github.com/JabRef/jabref/issues/10984)
+
 
 ### Changed
 
diff --git a/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java b/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java
index 4da18163ab2..18972ba26c5 100644
--- a/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java
+++ b/src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java
@@ -1,6 +1,7 @@
 package org.jabref.gui.fieldeditors;
 
 import java.util.Comparator;
+import java.util.Optional;
 
 import javax.swing.undo.UndoManager;
 
@@ -12,6 +13,10 @@
 import javafx.scene.control.ContentDisplay;
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.Label;
+import javafx.scene.input.ClipboardContent;
+import javafx.scene.input.DragEvent;
+import javafx.scene.input.Dragboard;
+import javafx.scene.input.TransferMode;
 import javafx.scene.layout.HBox;
 
 import org.jabref.gui.ClipBoardManager;
@@ -22,16 +27,21 @@
 import org.jabref.gui.actions.StandardActions;
 import org.jabref.gui.autocompleter.SuggestionProvider;
 import org.jabref.gui.icon.IconTheme;
+import org.jabref.gui.keyboard.KeyBinding;
+import org.jabref.gui.keyboard.KeyBindingRepository;
 import org.jabref.gui.util.ViewModelListCellFactory;
 import org.jabref.logic.integrity.FieldCheckers;
 import org.jabref.logic.l10n.Localization;
 import org.jabref.logic.preferences.CliPreferences;
 import org.jabref.model.entry.BibEntry;
 import org.jabref.model.entry.Keyword;
+import org.jabref.model.entry.KeywordList;
 import org.jabref.model.entry.field.Field;
 
+import com.airhacks.afterburner.injection.Injector;
 import com.airhacks.afterburner.views.ViewLoader;
 import com.dlsc.gemsfx.TagsField;
+import com.google.common.collect.Comparators;
 import jakarta.inject.Inject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,6 +58,9 @@ public class KeywordsEditor extends HBox implements FieldEditorFX {
     @Inject private UndoManager undoManager;
     @Inject private ClipBoardManager clipBoardManager;
 
+    private boolean isSortedTagsField = false;
+    private Optional<Keyword> draggedKeyword = Optional.empty();
+
     public KeywordsEditor(Field field,
                           SuggestionProvider<?> suggestionProvider,
                           FieldCheckers fieldCheckers) {
@@ -87,6 +100,29 @@ public KeywordsEditor(Field field,
             }
         });
 
+        this.viewModel.keywordListProperty().addListener((observable, oldValue, newValue) -> {
+            if (keywordTagsField.getTags().size() < 2) {
+                isSortedTagsField = false;
+            } else if ((Comparators.isInOrder(keywordTagsField.getTags(), Comparator.comparing(Keyword::get))) || isSortedTagsField) {
+                isSortedTagsField = true;
+                keywordTagsField.getTags().sort(Comparator.comparing(Keyword::get));
+            }
+        });
+
+        keywordTagsField.getEditor().setOnKeyPressed(event -> {
+            KeyBindingRepository keyBindingRepository = Injector.instantiateModelOrService(KeyBindingRepository.class);
+
+            if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.PASTE, event)) {
+                String clipboardText = clipBoardManager.getContents();
+                if (!clipboardText.isEmpty()) {
+                    KeywordList keywordsList = KeywordList.parse(clipboardText, viewModel.getKeywordSeparator());
+                    keywordsList.stream().forEach(keyword -> keywordTagsField.addTags(keyword));
+                    keywordTagsField.getEditor().clear();
+                    event.consume();
+                }
+            }
+        });
+
         Bindings.bindContentBidirectional(keywordTagsField.getTags(), viewModel.keywordListProperty());
     }
 
@@ -104,6 +140,46 @@ private Node createTag(Keyword keyword) {
                 factory.createMenuItem(StandardActions.DELETE, new KeywordsEditor.TagContextAction(StandardActions.DELETE, keyword))
         );
         tagLabel.setContextMenu(contextMenu);
+        tagLabel.setOnMouseClicked(event -> {
+            if (event.getClickCount() == 2) {
+                keywordTagsField.removeTags(keyword);
+                keywordTagsField.getEditor().setText(keyword.get());
+                keywordTagsField.getEditor().positionCaret(keyword.get().length());
+            }
+        });
+        tagLabel.setOnDragOver(event -> {
+            if (event.getGestureSource() != tagLabel && event.getDragboard().hasString()) {
+                event.acceptTransferModes(TransferMode.MOVE);
+            }
+            event.consume();
+        });
+        tagLabel.setOnDragDetected(event -> {
+            Dragboard db = tagLabel.startDragAndDrop(TransferMode.MOVE);
+            ClipboardContent content = new ClipboardContent();
+            content.putString(keyword.get());
+            db.setContent(content);
+            draggedKeyword = Optional.of(keyword);
+            event.consume();
+        });
+        tagLabel.setOnDragEntered(event -> tagLabel.setStyle("-fx-background-color: lightgrey;"));
+        tagLabel.setOnDragExited(event -> tagLabel.setStyle(""));
+        tagLabel.setOnDragDropped(event -> {
+            Dragboard db = event.getDragboard();
+            if (db.hasString() && draggedKeyword.isPresent()) {
+                int oldIndex = keywordTagsField.getTags().indexOf(draggedKeyword.get());
+                int dropIndex = keywordTagsField.getTags().indexOf(keyword);
+                if (oldIndex != dropIndex) {
+                    keywordTagsField.removeTags(draggedKeyword.get());
+                    keywordTagsField.getTags().add(dropIndex, draggedKeyword.get());
+                }
+                event.setDropCompleted(true);
+            } else {
+                event.setDropCompleted(false);
+            }
+            draggedKeyword = Optional.empty();
+            event.consume();
+        });
+        tagLabel.setOnDragDone(DragEvent::consume);
         return tagLabel;
     }
 
@@ -141,18 +217,18 @@ public void execute() {
                 case COPY -> {
                     clipBoardManager.setContent(keyword.get());
                     dialogService.notify(Localization.lang("Copied '%0' to clipboard.",
-                            JabRefDialogService.shortenDialogMessage(keyword.get())));
+                                                           JabRefDialogService.shortenDialogMessage(keyword.get())));
                 }
                 case CUT -> {
                     clipBoardManager.setContent(keyword.get());
                     dialogService.notify(Localization.lang("Copied '%0' to clipboard.",
-                            JabRefDialogService.shortenDialogMessage(keyword.get())));
+                                                           JabRefDialogService.shortenDialogMessage(keyword.get())));
                     keywordTagsField.removeTags(keyword);
                 }
                 case DELETE ->
-                        keywordTagsField.removeTags(keyword);
+                    keywordTagsField.removeTags(keyword);
                 default ->
-                        LOGGER.info("Action {} not defined", command.getText());
+                    LOGGER.info("Action {} not defined", command.getText());
             }
         }
     }


Reviews:
user: login: subhramit
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T22:43:48Z
user: login: subhramit
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T22:44:19Z
user: login: github-actions[bot]
body: Your code currently does not meet [JabRef's code guidelines](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html). We use [Checkstyle](https://checkstyle.sourceforge.io/) to identify issues. Please carefully follow [the setup guide for the codestyle](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html). Afterwards, please [run checkstyle locally](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html#run-checkstyle) and fix the issues.
In case of issues with the import order, double check that you [activated Auto Import](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-13-code-style.html#enable-proper-import-cleanup). You can trigger fixing imports by pressing <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>O</kbd> to trigger [Optimize Imports](https://www.jetbrains.com/guide/tips/optimize-imports/).

state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T00:08:50Z
user: login: Siedlerchr
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-07T14:18:02Z

Review comments:
diff_hunk: @@ -87,6 +99,29 @@ public KeywordsEditor(Field field,
             }
         });
 
+        this.viewModel.keywordListProperty().addListener((observable, oldValue, newValue) -> {
+            if (keywordTagsField.getTags().size() < 2) {
+                isSortedTagsField = false;
+            } else if ((Comparators.isInOrder(keywordTagsField.getTags(), Comparator.comparing(Keyword::get))) || isSortedTagsField) {
+                isSortedTagsField = true;
+                keywordTagsField.getTags().sort(Comparator.comparing(Keyword::get));
+            }
+        });
+
+        keywordTagsField.getEditor().setOnKeyPressed(evt -> {
+            KeyBindingRepository keyBindingRepository = Injector.instantiateModelOrService(KeyBindingRepository.class);
+
+            if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.PASTE, evt)) {
path: src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java
user: login: subhramit
body: Please expand the abbreviation "evt"
created_at: 2025-03-06T22:43:48Z
author_association: MEMBER
diff_hunk: @@ -104,6 +139,46 @@ private Node createTag(Keyword keyword) {
                 factory.createMenuItem(StandardActions.DELETE, new KeywordsEditor.TagContextAction(StandardActions.DELETE, keyword))
         );
         tagLabel.setContextMenu(contextMenu);
+        tagLabel.setOnMouseClicked(event -> {
+            if (event.getClickCount() == 2) {
+                keywordTagsField.removeTags(keyword);
+                keywordTagsField.getEditor().setText(keyword.get());
+                keywordTagsField.getEditor().positionCaret(keyword.get().length());
+            }
+        });
+        tagLabel.setOnDragOver(event -> {
+            if (event.getGestureSource() != tagLabel && event.getDragboard().hasString()) {
+                event.acceptTransferModes(TransferMode.MOVE);
+            }
+            event.consume();
+        });
+        tagLabel.setOnDragDetected(event -> {
+            Dragboard db = tagLabel.startDragAndDrop(TransferMode.MOVE);
+            ClipboardContent content = new ClipboardContent();
+            content.putString(keyword.get());
+            db.setContent(content);
+            draggedKeyword = keyword;
+            event.consume();
+        });
+        tagLabel.setOnDragEntered(event -> tagLabel.setStyle("-fx-background-color: lightgrey;"));
+        tagLabel.setOnDragExited(event -> tagLabel.setStyle(""));
+        tagLabel.setOnDragDropped(event -> {
+            Dragboard db = event.getDragboard();
+            if (db.hasString() && draggedKeyword != null) {
+                int oldIndex = keywordTagsField.getTags().indexOf(draggedKeyword);
+                int dropIndex = keywordTagsField.getTags().indexOf(keyword);
+                if (oldIndex != dropIndex) {
+                    keywordTagsField.removeTags(draggedKeyword);
+                    keywordTagsField.getTags().add(dropIndex, draggedKeyword);
+                }
+                event.setDropCompleted(true);
+            } else {
+                event.setDropCompleted(false);
+            }
+            draggedKeyword = null;
path: src/main/java/org/jabref/gui/fieldeditors/KeywordsEditor.java
user: login: subhramit
body: I would prefer using `Optional<Keyword>` instead of `Keyword` for `draggedKeyword`.
created_at: 2025-03-06T22:44:19Z
author_association: MEMBER

PR comments:
user: login: trag-bot[bot]
created_at: 2025-03-07T00:47:01Z
body: @trag-bot didn't find any issues in the code! ✅✨
author_association: NONE
user: login: trag-bot[bot]
created_at: 2025-03-07T00:47:16Z
body: ### Pull request summary

- Added a new feature to reorder keywords using drag-and-drop functionality in the keyword editor.
- Implemented automatic alphabetical sorting of keywords when they are added or modified.
- Enhanced the pasting functionality to allow multiple keywords to be pasted from the clipboard.
- Introduced a listener to manage the state of the keyword list and ensure it remains sorted.
- Updated the context menu to support keyword actions such as copy, cut, and delete.
- Improved user interaction by allowing double-clicking on keywords to edit them directly.
- Added visual feedback during drag-and-drop operations for better user experience.
- Ensured that the integrity of the keyword list is maintained during drag-and-drop actions.
author_association: NONE
user: login: Lin-Hi
created_at: 2025-03-07T01:00:03Z
body: Hi, I change code according to your reviews. Contact if there's more problem.
author_association: CONTRIBUTOR
user: login: Siedlerchr
created_at: 2025-03-07T14:38:00Z
body: Thanks for your work!
author_association: MEMBER