Skip to content

Allow drag and drop of Windows shortcut (.lnk) files #15053

Merged
koppor merged 14 commits into
JabRef:mainfrom
faneeshh:fix-for-issue-15036
Mar 16, 2026
Merged

Allow drag and drop of Windows shortcut (.lnk) files #15053
koppor merged 14 commits into
JabRef:mainfrom
faneeshh:fix-for-issue-15036

Conversation

@faneeshh

@faneeshh faneeshh commented Feb 8, 2026

Copy link
Copy Markdown
Collaborator

Related issues and pull requests

Closes #15036

PR Description

JabRef already opens .lnk files but dragging and dropping them onto the main window wasn't working because the shortcut file itself was being passed to the BibTeX parser instead of the target .bib file. This fix resolves .lnk shortcuts using the mslinks library before passing them to the file open logic.

Steps to test

  1. Create a .bib file on your Windows desktop (e.g., test.bib).
  2. Right click the file and select "Create shortcut".
  3. Open JabRef and drag the .lnk file onto the main window.
  4. The library should open successfully
2026-02-27.13-35-50.mp4

Checklist

  • I own the copyright of the code submitted and I license it under the MIT license
  • I manually tested my changes in running JabRef (always required)
  • I added JUnit tests for changes (if applicable)
  • I added screenshots in the PR description (if change is visible to the user)
  • [/] I added a screenshot in the PR description showing a library with a single entry with me as author and as title the issue number
  • I described the change in CHANGELOG.md in a way that can be understood by the average user (if change is visible to the user)
  • I checked the user documentation for up to dateness and submitted a pull request to our user documentation repository

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Support drag and drop of Windows shortcut (.lnk) files

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add support for dragging and dropping Windows shortcut (.lnk) files
• Resolve .lnk shortcuts to target .bib files using PowerShell
• Update FrameDndHandler and MainTable to handle shortcut resolution
• Add utility methods in FileUtil for shortcut detection and resolution
Diagram
flowchart LR
  A["User drags .lnk file"] --> B["FrameDndHandler/MainTable receives file"]
  B --> C["FileUtil.isShortcutFile checks extension"]
  C --> D["FileUtil.resolveWindowsShortcut uses PowerShell"]
  D --> E["Target .bib file path returned"]
  E --> F["Library opens with entries"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java ✨ Enhancement +19/-1

Add shortcut resolution to drag-drop handler

• Modified getBibFiles() method to handle shortcut file resolution
• Added flatMap logic to resolve .lnk files to their targets
• Added isAcceptedFile() helper method to check for .bib or .lnk files
• Imported Stream class for stream operations

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java


2. jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java ✨ Enhancement +3/-2

Integrate shortcut resolution in MainTable drag-drop

• Updated handleOnDragDropped() to resolve shortcuts before processing
• Updated handleOnDragDroppedTableView() to resolve shortcuts before import
• Added import for FileUtil class
• Both methods now call FileUtil.resolveWindowsShortcuts() on dropped files

jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java


3. jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java ✨ Enhancement +74/-0

Add Windows shortcut detection and resolution utilities

• Added isShortcutFile() method to detect .lnk files by extension
• Added resolveWindowsShortcut() method using PowerShell to resolve shortcuts
• Added resolveWindowsShortcuts() utility method to batch resolve multiple paths
• PowerShell implementation handles Windows-only execution with proper error handling

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java


View more (1)
4. CHANGELOG.md 📝 Documentation +1/-0

Document shortcut drag-drop feature

• Added entry documenting support for drag and drop of Windows shortcut files
• References issue #15036 with proper link formatting

CHANGELOG.md


Grey Divider

Qodo Logo

@github-actions github-actions Bot added the good first issue An issue intended for project-newcomers. Varies in difficulty. label Feb 8, 2026
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Feb 8, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (6) 📎 Requirement gaps (0)

Grey Divider


Action required

1. .lnk accepted on non-Windows platforms🐞 Bug ✓ Correctness
Description
isAcceptedFile() calls FileUtil.isShortcutFile() with no OS guard. On macOS/Linux a dropped
.lnk file passes the filter, but resolveIfShortcut() is a no-op there and returns the original
.lnk path, which is then fed to the BibTeX parser producing confusing parse errors.
Code

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[R242-244]

+    private boolean isAcceptedFile(Path path) {
+        return FileUtil.isBibFile(path) || FileUtil.isShortcutFile(path);
+    }
Evidence
isShortcutFile() only checks the file extension with no OS check, so it returns true on any
platform. resolveIfShortcut() immediately returns the original path when !OS.WINDOWS, so the
.lnk binary is never resolved. openTheFile() only guards on Files.exists(), so the binary
.lnk content reaches the BibTeX parser.

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[530-532]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[540-543]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`isAcceptedFile()` in `FrameDndHandler` accepts `.lnk` files on all operating systems because `FileUtil.isShortcutFile()` only checks the file extension. On non-Windows systems `resolveIfShortcut()` is a no-op and returns the original `.lnk` binary path, which is then parsed as BibTeX.
## Issue Context
- `FileUtil.isShortcutFile()` has no OS check (extension-only test).
- `FileUtil.resolveIfShortcut()` guards with `!OS.WINDOWS` and returns the original path immediately on non-Windows.
- `openTheFile()` only checks `Files.exists()`, so the `.lnk` binary reaches the parser.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
Change the method to:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. No .bib validation after shortcut resolution🐞 Bug ✓ Correctness
Description
After resolving a .lnk shortcut, the code never checks whether the resolved target is a .bib
file. A shortcut pointing to a .pdf, .docx, or any other file type is silently forwarded to
openTheFile() and parsed as a BibTeX database, producing confusing errors with no explanation.
Code

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[R168-171]

+        // Resolve any shortcuts to their targets
+        List<Path> resolvedFiles = filesToOpen.stream()
+                                              .map(FileUtil::resolveIfShortcut)
+                                              .collect(Collectors.toList());
Evidence
Before this PR, getBibFiles() applied filter(FileUtil::isBibFile), guaranteeing only .bib
files reached openFiles(). The new code replaces that filter with isAcceptedFile() (which admits
all .lnk files), and openFiles() maps resolveIfShortcut over the list but never re-validates
the resolved extension before calling openTheFile(). openTheFile() only checks Files.exists(),
so any non-.bib resolved target is parsed as BibTeX.

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-201]
jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After `resolveIfShortcut()` maps each path to its target, there is no check that the resolved target is actually a `.bib` file. A `.lnk` pointing to a `.pdf` or any other file type will be passed to `openTheFile()` and parsed as BibTeX.
## Issue Context
- The old code used `filter(FileUtil::isBibFile)` in `getBibFiles()` to guarantee only `.bib` files reached `openFiles()`.
- The new code removes that guarantee: `isAcceptedFile()` admits all `.lnk` files, and `openFiles()` does not re-validate after resolution.
- `openTheFile()` only checks `Files.exists()` (line 220), not the file extension.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]
Add a `.bib` filter after resolution:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Failed resolution falls back to parsing .lnk binary🐞 Bug ⛯ Reliability
Description
When resolveIfShortcut() fails (exception thrown, or the shortcut target does not exist on disk),
it returns the original .lnk path. That path passes openTheFile()'s Files.exists() guard (the
.lnk file itself exists), so the binary .lnk content is fed to the BibTeX parser instead of
surfacing a clear "shortcut target not found" error. Broken/orphaned shortcuts are common in
real-world Windows usage.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R556-561]

+        } catch (IOException | ShellLinkException e) {
+            LOGGER.warn("Could not resolve shortcut {}", path, e);
+        }
+
+        return path;
+    }
Evidence
resolveIfShortcut() returns the original .lnk path in two failure cases: (1) an IOException or
ShellLinkException is caught, and (2) the resolved target path does not exist
(!Files.exists(resolvedPath)). In both cases the returned .lnk path is a real file on disk, so
openTheFile()'s Files.exists() guard is bypassed and the binary .lnk data is parsed as BibTeX.

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-560]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `resolveIfShortcut()` cannot resolve a shortcut (broken link, missing target, or parse exception), it returns the original `.lnk` path. This path passes `openTheFile()`&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;s `Files.exists()` check and the binary `.lnk` content is parsed as BibTeX, producing confusing errors instead of a clear failure message.
## Issue Context
- `resolveIfShortcut()` returns the original path on exception (line 556-560) and when the resolved target does not exist (line 552-554).
- The `.lnk` file itself exists on disk, so `openTheFile()`&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;s `Files.exists()` guard (line 220) does not filter it out.
- Broken shortcuts (target deleted or moved) are common in real-world Windows usage.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-561]
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]
Preferred fix — add `filter(FileUtil::isBibFile)` after resolution in `openFiles()` (covers both this issue and Finding 2):

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (23)
4. resolveWindowsShortcut catches Exception📘 Rule violation ⛯ Reliability
Description
resolveWindowsShortcut wraps the whole PowerShell invocation in a broad catch (Exception) and
degrades by returning Optional.empty(), which can silently drop .lnk files during drag-and-drop
without a clear recovery path. • The method blocks on process.waitFor() with no timeout and does
not restore the interrupt flag on interruption, which risks hangs and makes failures harder to
diagnose reliably. • This violates the requirement for specific, non-disruptive exception handling
and robust edge-case management around external process execution.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R548-584]

+        try {
+            // Use PowerShell to resolve the shortcut target
+            ProcessBuilder pb = new ProcessBuilder(
+                    "powershell", "-NoProfile", "-Command",
+                    "$ws = New-Object -ComObject WScript.Shell; " +
+                            "$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
+                            "Write-Output $shortcut.TargetPath"
+            );
+
+            pb.redirectErrorStream(true);
+            Process process = pb.start();
+
+            String targetPath;
+            try (java.io.BufferedReader reader = new java.io.BufferedReader(
+                    new java.io.InputStreamReader(process.getInputStream()))) {
+                targetPath = reader.readLine();
+            }
+
+            int exitCode = process.waitFor();
+
+            if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
+                Path resolvedPath = Path.of(targetPath.trim());
+                if (Files.exists(resolvedPath)) {
+                    LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
+                    return Optional.of(resolvedPath);
+                } else {
+                    LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
+                    return Optional.empty();
+                }
+            } else {
+                LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
+                return Optional.empty();
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
+            return Optional.empty();
+        }
Evidence
The compliance checklist requires specific exception handling and robust handling of failure points.
The new code uses a broad catch (Exception) and performs an unbounded waitFor(), returning empty
results on failures, which can lead to silent failures and potential hangs.

Rule 3: Generic: Robust Error Handling and Edge Case Management
AGENTS.md
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[566-566]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[581-583]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FileUtil.resolveWindowsShortcut` catches a broad `Exception` and blocks on `process.waitFor()` without a timeout. This can lead to silent failures (returning `Optional.empty()`), and it risks hanging the application thread.
## Issue Context
The shortcut resolution executes an external process (PowerShell) which is a high-failure-risk dependency (missing executable, permission issues, COM errors, long-running/hung process). Exception handling should be specific and interruptions should preserve the thread interrupt status.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[548-584]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Missing tests for .lnk📘 Rule violation ✓ Correctness
Description
• New behavior was introduced for resolving Windows shortcuts via
FileUtil.resolveWindowsShortcut/resolveWindowsShortcuts and used in drag-and-drop flows, but no
corresponding JUnit tests were added/updated to cover this behavior. • The existing FileUtilTest
covers file extension handling, yet does not include .lnk cases, leaving key edge cases
(non-Windows behavior, failure modes) unverified.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R524-596]

+    /// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
+    ///
+    /// @param file The file to check
+    /// @return True if file extension is ".lnk", false otherwise
+    public static boolean isShortcutFile(Path file) {
+        return getFileExtension(file).filter("lnk"::equals).isPresent();
+    }
+
+    /// Resolves a Windows shortcut (.lnk) file to its target path.
+    /// Only works on Windows systems. On other systems or if resolution fails, returns empty Optional.
+    ///
+    /// @param shortcutPath The path to the .lnk file
+    /// @return Optional containing the target path, or empty if resolution fails
+    public static Optional<Path> resolveWindowsShortcut(Path shortcutPath) {
+        if (!isShortcutFile(shortcutPath)) {
+            return Optional.empty();
+        }
+
+        // Only attempt on Windows
+        if (!OS.WINDOWS) {
+            LOGGER.debug("Shortcut resolution only supported on Windows");
+            return Optional.empty();
+        }
+
+        try {
+            // Use PowerShell to resolve the shortcut target
+            ProcessBuilder pb = new ProcessBuilder(
+                    "powershell", "-NoProfile", "-Command",
+                    "$ws = New-Object -ComObject WScript.Shell; " +
+                            "$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
+                            "Write-Output $shortcut.TargetPath"
+            );
+
+            pb.redirectErrorStream(true);
+            Process process = pb.start();
+
+            String targetPath;
+            try (java.io.BufferedReader reader = new java.io.BufferedReader(
+                    new java.io.InputStreamReader(process.getInputStream()))) {
+                targetPath = reader.readLine();
+            }
+
+            int exitCode = process.waitFor();
+
+            if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
+                Path resolvedPath = Path.of(targetPath.trim());
+                if (Files.exists(resolvedPath)) {
+                    LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
+                    return Optional.of(resolvedPath);
+                } else {
+                    LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
+                    return Optional.empty();
+                }
+            } else {
+                LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
+                return Optional.empty();
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
+            return Optional.empty();
+        }
+    }
+
+    public static List<Path> resolveWindowsShortcuts(List<Path> paths) {
+        return paths.stream()
+                    .flatMap(path -> {
+                        if (isShortcutFile(path)) {
+                            return resolveWindowsShortcut(path).stream();
+                        }
+                        return Stream.of(path);
+                    })
+                    .toList();
+    }
Evidence
The checklist requires appropriate tests for behavior changes. The PR adds new shortcut-resolution
behavior in FileUtil, but existing FileUtilTest extension cases do not include .lnk,
indicating the new functionality is not covered by tests.

AGENTS.md
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-596]
jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[179-190]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New Windows shortcut (`.lnk`) drag-and-drop support introduces new `FileUtil` behavior without corresponding test coverage.
## Issue Context
At minimum, tests should cover:
- `isShortcutFile` correctly detecting `.lnk` (case handling if intended)
- `resolveWindowsShortcuts` returning the original paths for non-shortcut inputs
- non-Windows behavior: `resolveWindowsShortcut` should return `Optional.empty()` without throwing
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-596]
- jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[179-210]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Case-sensitive .lnk check🐞 Bug ✓ Correctness
Description
isShortcutFile uses exact string match ("lnk"::equals) but getFileExtension does not
actually lowercase the extension, despite its documentation. • As a result, shortcuts like
FILE.LNK may not be recognized, breaking the new drag-and-drop behavior on Windows.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R524-530]

+    /// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
+    ///
+    /// @param file The file to check
+    /// @return True if file extension is ".lnk", false otherwise
+    public static boolean isShortcutFile(Path file) {
+        return getFileExtension(file).filter("lnk"::equals).isPresent();
+    }
Evidence
The extension helper claims to return lowercase but returns the raw extension from FilenameUtils.
The shortcut predicate compares with a lowercase literal using a case-sensitive equals.

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[74-94]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-530]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`.lnk` detection is effectively case-sensitive because `getFileExtension` returns the raw extension and `isShortcutFile` compares using `&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;lnk&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;::equals`.
### Issue Context
Windows file extensions are case-insensitive and `.LNK` is common. The current implementation can fail to detect valid shortcuts.
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[74-94]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-530]
### Suggested approach
- Update `getFileExtension` to return `extension.toLowerCase(Locale.ROOT)` (and adjust imports/tests accordingly), aligning with its Javadoc.
- Alternatively, change `isShortcutFile` to `filter(ext -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; ext.equalsIgnoreCase(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;lnk&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;))` (but prefer central normalization in `getFileExtension`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Shortcut returns non-file🐞 Bug ✓ Correctness
Description
resolveWindowsShortcut returns any existing target path, including directories, because it only
checks Files.exists. • Downstream import/link logic in ImportHandler treats unknown paths by
creating an empty entry with a file link, which can create incorrect entries if a shortcut points to
a directory.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R568-573]

+            if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
+                Path resolvedPath = Path.of(targetPath.trim());
+                if (Files.exists(resolvedPath)) {
+                    LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
+                    return Optional.of(resolvedPath);
+                } else {
Evidence
The resolver returns paths that exist without verifying they are regular files. ImportHandler
creates an entry for non-PDF/non-BIB paths, which would include directories returned by the
resolver.

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[568-573]
jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java[183-199]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Shortcut resolution currently returns any existing path, including directories. This can leak directory targets into file-import/link flows, creating empty entries with folder links.
### Issue Context
`ImportHandler` treats unknown paths as generic files and creates an empty entry with a link, which is incorrect when the path is a folder.
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[568-576]
- jabgui/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java[183-199]
### Suggested approach
- Replace `Files.exists(resolvedPath)` with `Files.isRegularFile(resolvedPath)` (or `Files.isRegularFile(resolvedPath, LinkOption.NOFOLLOW_LINKS)` if appropriate).
- Consider logging a clear warning when the shortcut target is not a regular file.
- Optionally: for callers that can accept directories, add an explicit parameter/alternate method rather than returning directories by default.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Path.of(targetPath) may crash 📘 Rule violation ⛯ Reliability
Description
resolveIfShortcut calls Path.of(targetPath) without handling InvalidPathException, which can
crash the app for malformed/unsupported shortcut targets. This violates the requirement to handle
edge cases and missing/invalid external input safely.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R549-555]

+            if (targetPath != null && !targetPath.isEmpty()) {
+                Path resolvedPath = Path.of(targetPath);
+
+                if (Files.exists(resolvedPath) && !Files.isDirectory(resolvedPath)) {
+                    return resolvedPath;
+                }
+            }
Evidence
The compliance checklist requires explicit handling of failure points and edge cases; the new code
constructs a Path from an externally-provided shortcut target string without guarding against
invalid path values, and only catches IOException | ShellLinkException.

Rule 3: Generic: Robust Error Handling and Edge Case Management
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-555]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FileUtil.resolveIfShortcut` converts the shortcut target string to a `Path` using `Path.of(targetPath)` without handling `InvalidPathException`. If a `.lnk` points to an invalid/unsupported path string, this can throw an unchecked exception and crash the flow.
## Issue Context
The shortcut target is external/untrusted data coming from the `.lnk` file. The method currently only catches `IOException | ShellLinkException`.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[545-561]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. resolveIfShortcut on UI thread📘 Rule violation ➹ Performance
Description
Drag-and-drop handlers call FileUtil.resolveIfShortcut synchronously while processing JavaFX drag
events, which may perform filesystem IO and block the UI thread. This risks UI freezes during
drag/drop operations.
Code

jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java[R541-545]

if (event.getDragboard().hasFiles()) {
-            List<Path> files = event.getDragboard().getFiles().stream().map(File::toPath).collect(Collectors.toList());
+            List<Path> files = event.getDragboard().getFiles().stream()
+                                    .map(File::toPath)
+                                    .map(FileUtil::resolveIfShortcut)
+                                    .collect(Collectors.toList());
Evidence
The compliance rule requires avoiding long/blocking work on the UI thread; the GUI layer now invokes
shortcut resolution during drag handling, and the resolver reads/parses the .lnk file.

jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java[541-545]
jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[545-548]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The UI drag-and-drop handlers synchronously resolve `.lnk` shortcuts, which can involve filesystem IO and block the JavaFX UI thread.
## Issue Context
`FileUtil.resolveIfShortcut` parses `.lnk` files via `mslinks.ShellLink`, which may be slow and should not run during UI event handling.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java[541-545]
- jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[238-244]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[540-561]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Uppercase .BIB not opened 🐞 Bug ✓ Correctness
Description
OpenDatabaseAction.openFiles now filters files with FileUtil.isBibFile, which is effectively
case-sensitive because getFileExtension returns the raw extension. This can cause valid libraries
like "FILE.BIB" (or other non-lowercase variants) to no longer open or raise an already-open tab.
Code

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[R168-173]

+        // Resolve any shortcuts to their targets and filter to only .bib files.
+        // The resulting list must remain modifiable for downstream processing (iterator.remove() calls below).
+        List<Path> resolvedFiles = filesToOpen.stream()
+                                              .map(FileUtil::resolveIfShortcut)
+                                              .filter(FileUtil::isBibFile)
+                                              .collect(Collectors.toList());
Evidence
openFiles now filters to only files where FileUtil.isBibFile returns true. isBibFile checks for an
exact "bib" match, while getFileExtension returns the extension without lowercasing, so
mixed/uppercase extensions will be filtered out even though the actual open path (openTheFile) does
not require a .bib extension to proceed.

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[163-174]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[518-524]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[76-96]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[216-224]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`OpenDatabaseAction.openFiles` now filters inputs using `FileUtil.isBibFile`. Because `isBibFile` does an exact match against &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;bib&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot; and `getFileExtension` returns the raw extension (not lowercased), valid libraries like `MYLIB.BIB` can be filtered out and therefore will no longer open.
### Issue Context
Before this PR, `openFiles` would open any existing file path (no extension gate). The new filter is intended to prevent trying to open `.lnk` binaries as libraries, but it introduces a regression for mixed/uppercase extensions.
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[76-96]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[518-524]
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-173]
- jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[423-433]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. .lnk accepted on non-Windows platforms🐞 Bug ✓ Correctness
Description
isAcceptedFile() calls FileUtil.isShortcutFile() with no OS guard. On macOS/Linux a dropped
.lnk file passes the filter, but resolveIfShortcut() is a no-op there and returns the original
.lnk path, which is then fed to the BibTeX parser producing confusing parse errors.
Code

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[R242-244]

+    private boolean isAcceptedFile(Path path) {
+        return FileUtil.isBibFile(path) || FileUtil.isShortcutFile(path);
+    }
Evidence
isShortcutFile() only checks the file extension with no OS check, so it returns true on any
platform. resolveIfShortcut() immediately returns the original path when !OS.WINDOWS, so the
.lnk binary is never resolved. openTheFile() only guards on Files.exists(), so the binary
.lnk content reaches the BibTeX parser.

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[530-532]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[540-543]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`isAcceptedFile()` in `FrameDndHandler` accepts `.lnk` files on all operating systems because `FileUtil.isShortcutFile()` only checks the file extension. On non-Windows systems `resolveIfShortcut()` is a no-op and returns the original `.lnk` binary path, which is then parsed as BibTeX.
## Issue Context
- `FileUtil.isShortcutFile()` has no OS check (extension-only test).
- `FileUtil.resolveIfShortcut()` guards with `!OS.WINDOWS` and returns the original path immediately on non-Windows.
- `openTheFile()` only checks `Files.exists()`, so the `.lnk` binary reaches the parser.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
Change the method to:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. No .bib validation after shortcut resolution🐞 Bug ✓ Correctness
Description
After resolving a .lnk shortcut, the code never checks whether the resolved target is a .bib
file. A shortcut pointing to a .pdf, .docx, or any other file type is silently forwarded to
openTheFile() and parsed as a BibTeX database, producing confusing errors with no explanation.
Code

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[R168-171]

+        // Resolve any shortcuts to their targets
+        List<Path> resolvedFiles = filesToOpen.stream()
+                                              .map(FileUtil::resolveIfShortcut)
+                                              .collect(Collectors.toList());
Evidence
Before this PR, getBibFiles() applied filter(FileUtil::isBibFile), guaranteeing only .bib
files reached openFiles(). The new code replaces that filter with isAcceptedFile() (which admits
all .lnk files), and openFiles() maps resolveIfShortcut over the list but never re-validates
the resolved extension before calling openTheFile(). openTheFile() only checks Files.exists(),
so any non-.bib resolved target is parsed as BibTeX.

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-201]
jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After `resolveIfShortcut()` maps each path to its target, there is no check that the resolved target is actually a `.bib` file. A `.lnk` pointing to a `.pdf` or any other file type will be passed to `openTheFile()` and parsed as BibTeX.
## Issue Context
- The old code used `filter(FileUtil::isBibFile)` in `getBibFiles()` to guarantee only `.bib` files reached `openFiles()`.
- The new code removes that guarantee: `isAcceptedFile()` admits all `.lnk` files, and `openFiles()` does not re-validate after resolution.
- `openTheFile()` only checks `Files.exists()` (line 220), not the file extension.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]
Add a `.bib` filter after resolution:

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. Failed resolution falls back to parsing .lnk binary🐞 Bug ⛯ Reliability
Description
When resolveIfShortcut() fails (exception thrown, or the shortcut target does not exist on disk),
it returns the original .lnk path. That path passes openTheFile()'s Files.exists() guard (the
.lnk file itself exists), so the binary .lnk content is fed to the BibTeX parser instead of
surfacing a clear "shortcut target not found" error. Broken/orphaned shortcuts are common in
real-world Windows usage.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R556-561]

+        } catch (IOException | ShellLinkException e) {
+            LOGGER.warn("Could not resolve shortcut {}", path, e);
+        }
+
+        return path;
+    }
Evidence
resolveIfShortcut() returns the original .lnk path in two failure cases: (1) an IOException or
ShellLinkException is caught, and (2) the resolved target path does not exist
(!Files.exists(resolvedPath)). In both cases the returned .lnk path is a real file on disk, so
openTheFile()'s Files.exists() guard is bypassed and the binary .lnk data is parsed as BibTeX.

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-560]
jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[219-222]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `resolveIfShortcut()` cannot resolve a shortcut (broken link, missing target, or parse exception), it returns the original `.lnk` path. This path passes `openTheFile()`&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;s `Files.exists()` check and the binary `.lnk` content is parsed as BibTeX, producing confusing errors instead of a clear failure message.
## Issue Context
- `resolveIfShortcut()` returns the original path on exception (line 556-560) and when the resolved target does not exist (line 552-554).
- The `.lnk` file itself exists on disk, so `openTheFile()`&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#x27;s `Files.exists()` guard (line 220) does not filter it out.
- Broken shortcuts (target deleted or moved) are common in real-world Windows usage.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-561]
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]
Preferred fix — add `filter(FileUtil::isBibFile)` after resolution in `openFiles()` (covers both this issue and Finding 2):

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


14. resolveWindowsShortcut catches Exception📘 Rule violation ⛯ Reliability
Description
resolveWindowsShortcut wraps the whole PowerShell invocation in a broad catch (Exception) and
degrades by returning Optional.empty(), which can silently drop .lnk files during drag-and-drop
without a clear recovery path. • The method blocks on process.waitFor() with no timeout and does
not restore the interrupt flag on interruption, which risks hangs and makes failures harder to
diagnose reliably. • This violates the requirement for specific, non-disruptive exception handling
and robust edge-case management around external process execution.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R548-584]

+        try {
+            // Use PowerShell to resolve the shortcut target
+            ProcessBuilder pb = new ProcessBuilder(
+                    "powershell", "-NoProfile", "-Command",
+                    "$ws = New-Object -ComObject WScript.Shell; " +
+                            "$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
+                            "Write-Output $shortcut.TargetPath"
+            );
+
+            pb.redirectErrorStream(true);
+            Process process = pb.start();
+
+            String targetPath;
+            try (java.io.BufferedReader reader = new java.io.BufferedReader(
+                    new java.io.InputStreamReader(process.getInputStream()))) {
+                targetPath = reader.readLine();
+            }
+
+            int exitCode = process.waitFor();
+
+            if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
+                Path resolvedPath = Path.of(targetPath.trim());
+                if (Files.exists(resolvedPath)) {
+                    LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
+                    return Optional.of(resolvedPath);
+                } else {
+                    LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
+                    return Optional.empty();
+                }
+            } else {
+                LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
+                return Optional.empty();
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
+            return Optional.empty();
+        }
Evidence
The compliance checklist requires specific exception handling and robust handling of failure points.
The new code uses a broad catch (Exception) and performs an unbounded waitFor(), returning empty
results on failures, which can lead to silent failures and potential hangs.

Rule 3: Generic: Robust Error Handling and Edge Case Management
AGENTS.md
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[566-566]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[581-583]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`FileUtil.resolveWindowsShortcut` catches a broad `Exception` and blocks on `process.waitFor()` without a timeout. This can lead to silent failures (returning `Optional.empty()`), and it risks hanging the application thread.
## Issue Context
The shortcut resolution executes an external process (PowerShell) which is a high-failure-risk dependency (missing executable, permission issues, COM errors, long-running/hung process). Exception handling should be specific and interruptions should preserve the thread interrupt status.
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[548-584]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


15. Missing tests for .lnk📘 Rule violation ✓ Correctness
Description
• New behavior was introduced for resolving Windows shortcuts via
FileUtil.resolveWindowsShortcut/resolveWindowsShortcuts and used in drag-and-drop flows, but no
corresponding JUnit tests were added/updated to cover this behavior. • The existing FileUtilTest
covers file extension handling, yet does not include .lnk cases, leaving key edge cases
(non-Windows behavior, failure modes) unverified.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R524-596]

+    /// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
+    ///
+    /// @param file The file to check
+    /// @return True if file extension is ".lnk", false otherwise
+    public static boolean isShortcutFile(Path file) {
+        return getFileExtension(file).filter("lnk"::equals).isPresent();
+    }
+
+    /// Resolves a Windows shortcut (.lnk) file to its target path.
+    /// Only works on Windows systems. On other systems or if resolution fails, returns empty Optional.
+    ///
+    /// @param shortcutPath The path to the .lnk file
+    /// @return Optional containing the target path, or empty if resolution fails
+    public static Optional<Path> resolveWindowsShortcut(Path shortcutPath) {
+        if (!isShortcutFile(shortcutPath)) {
+            return Optional.empty();
+        }
+
+        // Only attempt on Windows
+        if (!OS.WINDOWS) {
+            LOGGER.debug("Shortcut resolution only supported on Windows");
+            return Optional.empty();
+        }
+
+        try {
+            // Use PowerShell to resolve the shortcut target
+            ProcessBuilder pb = new ProcessBuilder(
+                    "powershell", "-NoProfile", "-Command",
+                    "$ws = New-Object -ComObject WScript.Shell; " +
+                            "$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
+                            "Write-Output $shortcut.TargetPath"
+            );
+
+            pb.redirectErrorStream(true);
+            Process process = pb.start();
+
+            String targetPath;
+            try (java.io.BufferedReader reader = new java.io.BufferedReader(
+                    new java.io.InputStreamReader(process.getInputStream()))) {
+                targetPath = reader.readLine();
+            }
+
+            int exitCode = process.waitFor();
+
+            if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
+                Path resolvedPath = Path.of(targetPath.trim());
+                if (Files.exists(resolvedPath)) {
+                    LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
+                    return Optional.of(resolvedPath);
+                } else {
+                    LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
+                    return Optional.empty();
+                }
+            } else {
+                LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
+                return Optional.empty();
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
+            return Optional.empty();
+        }
+    }
+
+    public static List<Path> resolveWindowsShortcuts(List<Path> paths) {
+        return paths.stream()
+                    .flatMap(path -> {
+                        if (isShortcutFile(path)) {
+                            return resolveWindowsShortcut(path).stream();
+                        }
+                        return Stream.of(path);
+                    })
+                    .toList();
+    }
Evidence
The checklist requires appropriate tests for behavior changes. The PR adds new shortcut-resolution
behavior in FileUtil, but existing FileUtilTest extension cases do not include .lnk,
indicating the new functionality is not covered by tests.

AGENTS.md
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-596]
jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[179-190]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New Windows shortcut (`.lnk`) drag-and-drop support introduces new `FileUtil` behavior without corresponding test coverage.
## Issue Context
At minimum, tests should cover:
- `isShortcutFile` correctly detecting `.lnk` (case handling if intended)
- `resolveWindowsShortcuts` returning the original paths for non-shortcut inputs
- non-Windows behavior: `resolveWindowsShortcut` should return `Optional.empty()` without throwing
## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-596]
- jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[179-210]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


16. Case-sensitive .lnk check🐞 Bug ✓ Correctness
Description
isShortcutFile uses exact string match ("lnk"::equals) but getFileExtension does not
actually lowercase the extension, despite its documentation. • As a result, shortcuts like
FILE.LNK may not be recognized, breaking the new drag-and-drop behavior on Windows.
Code

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[R524-530]

+    /// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
+    ///
+    /// @param file The file to check
+    /// @return True if file extension is ".lnk", false otherwise
+    public static boolean isShortcutFile(Path file) {
+        return getFileExtension(file).filter("lnk"::equals).isPresent();
+    }
Evidence
The extension helper claims to return lowercase but returns the raw extension from FilenameUtils.
The shortcut predicate compares with a lowercase literal using a case-sensitive equals.

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[74-94]
jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-530]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`.lnk` detection is effectively case-sensitive because `getFileExtension` returns the raw extension and `isShortcutFile` compares using `&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;lnk&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;::equals`.
### Issue Context
Windows file extensions are case-insensitive and `.LNK` is common. The current implementation can fail to detect valid shortcuts.
### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[74-94]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-530]
### Suggested approach
- Update `getFileExtension` to return `extension.toLowerCase(Locale.ROOT)` (and adjust imports/tests accordingly), aligning with its Javadoc.
- Alternatively, change `isShortcutFile` to `filter(ext -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; ext.equalsIgnoreCase(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;lnk&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;))` (but prefer central normalization in `getFileExtension`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


17. Path.of(targetPath) may crash 📘 Rule violation ⛯ Reliability
Description
resolveIfShortcut calls Path.of(targetPath) without handling InvalidPathException, which can
crash the app for malformed/unsupported shortcut targets. This violates the requirement to handle
edge cases and missing/invalid external input safely.
Code

[jablib/src/main/java/org/jabref/logic/util/io/FileUtil.jav...

Comment on lines +548 to +584
try {
// Use PowerShell to resolve the shortcut target
ProcessBuilder pb = new ProcessBuilder(
"powershell", "-NoProfile", "-Command",
"$ws = New-Object -ComObject WScript.Shell; " +
"$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
"Write-Output $shortcut.TargetPath"
);

pb.redirectErrorStream(true);
Process process = pb.start();

String targetPath;
try (java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream()))) {
targetPath = reader.readLine();
}

int exitCode = process.waitFor();

if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
Path resolvedPath = Path.of(targetPath.trim());
if (Files.exists(resolvedPath)) {
LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
return Optional.of(resolvedPath);
} else {
LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
return Optional.empty();
}
} else {
LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
return Optional.empty();
}
} catch (Exception e) {
LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
return Optional.empty();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. resolvewindowsshortcut catches exception 📘 Rule violation ⛯ Reliability

resolveWindowsShortcut wraps the whole PowerShell invocation in a broad catch (Exception) and
  degrades by returning Optional.empty(), which can silently drop .lnk files during drag-and-drop
  without a clear recovery path.
• The method blocks on process.waitFor() with no timeout and does not restore the interrupt flag
  on interruption, which risks hangs and makes failures harder to diagnose reliably.
• This violates the requirement for specific, non-disruptive exception handling and robust edge-case
  management around external process execution.
Agent Prompt
## Issue description
`FileUtil.resolveWindowsShortcut` catches a broad `Exception` and blocks on `process.waitFor()` without a timeout. This can lead to silent failures (returning `Optional.empty()`), and it risks hanging the application thread.

## Issue Context
The shortcut resolution executes an external process (PowerShell) which is a high-failure-risk dependency (missing executable, permission issues, COM errors, long-running/hung process). Exception handling should be specific and interruptions should preserve the thread interrupt status.

## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[548-584]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +524 to +596
/// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
///
/// @param file The file to check
/// @return True if file extension is ".lnk", false otherwise
public static boolean isShortcutFile(Path file) {
return getFileExtension(file).filter("lnk"::equals).isPresent();
}

/// Resolves a Windows shortcut (.lnk) file to its target path.
/// Only works on Windows systems. On other systems or if resolution fails, returns empty Optional.
///
/// @param shortcutPath The path to the .lnk file
/// @return Optional containing the target path, or empty if resolution fails
public static Optional<Path> resolveWindowsShortcut(Path shortcutPath) {
if (!isShortcutFile(shortcutPath)) {
return Optional.empty();
}

// Only attempt on Windows
if (!OS.WINDOWS) {
LOGGER.debug("Shortcut resolution only supported on Windows");
return Optional.empty();
}

try {
// Use PowerShell to resolve the shortcut target
ProcessBuilder pb = new ProcessBuilder(
"powershell", "-NoProfile", "-Command",
"$ws = New-Object -ComObject WScript.Shell; " +
"$shortcut = $ws.CreateShortcut('" + shortcutPath.toAbsolutePath().toString().replace("'", "''") + "'); " +
"Write-Output $shortcut.TargetPath"
);

pb.redirectErrorStream(true);
Process process = pb.start();

String targetPath;
try (java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream()))) {
targetPath = reader.readLine();
}

int exitCode = process.waitFor();

if (exitCode == 0 && targetPath != null && !targetPath.trim().isEmpty()) {
Path resolvedPath = Path.of(targetPath.trim());
if (Files.exists(resolvedPath)) {
LOGGER.debug("Resolved shortcut {} to {}", shortcutPath, resolvedPath);
return Optional.of(resolvedPath);
} else {
LOGGER.warn("Shortcut target does not exist: {}", resolvedPath);
return Optional.empty();
}
} else {
LOGGER.warn("Failed to resolve shortcut: {} (exit code: {})", shortcutPath, exitCode);
return Optional.empty();
}
} catch (Exception e) {
LOGGER.warn("Exception while resolving shortcut: {}", shortcutPath, e);
return Optional.empty();
}
}

public static List<Path> resolveWindowsShortcuts(List<Path> paths) {
return paths.stream()
.flatMap(path -> {
if (isShortcutFile(path)) {
return resolveWindowsShortcut(path).stream();
}
return Stream.of(path);
})
.toList();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Missing tests for .lnk 📘 Rule violation ✓ Correctness

• New behavior was introduced for resolving Windows shortcuts via
  FileUtil.resolveWindowsShortcut/resolveWindowsShortcuts and used in drag-and-drop flows, but no
  corresponding JUnit tests were added/updated to cover this behavior.
• The existing FileUtilTest covers file extension handling, yet does not include .lnk cases,
  leaving key edge cases (non-Windows behavior, failure modes) unverified.
Agent Prompt
## Issue description
New Windows shortcut (`.lnk`) drag-and-drop support introduces new `FileUtil` behavior without corresponding test coverage.

## Issue Context
At minimum, tests should cover:
- `isShortcutFile` correctly detecting `.lnk` (case handling if intended)
- `resolveWindowsShortcuts` returning the original paths for non-shortcut inputs
- non-Windows behavior: `resolveWindowsShortcut` should return `Optional.empty()` without throwing

## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-596]
- jablib/src/test/java/org/jabref/logic/util/io/FileUtilTest.java[179-210]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +524 to +530
/// Test if the file is a shortcut file by simply checking the extension to be ".lnk"
///
/// @param file The file to check
/// @return True if file extension is ".lnk", false otherwise
public static boolean isShortcutFile(Path file) {
return getFileExtension(file).filter("lnk"::equals).isPresent();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Case-sensitive .lnk check 🐞 Bug ✓ Correctness

isShortcutFile uses exact string match ("lnk"::equals) but getFileExtension does not
  actually lowercase the extension, despite its documentation.
• As a result, shortcuts like FILE.LNK may not be recognized, breaking the new drag-and-drop
  behavior on Windows.
Agent Prompt
### Issue description
`.lnk` detection is effectively case-sensitive because `getFileExtension` returns the raw extension and `isShortcutFile` compares using `"lnk"::equals`.

### Issue Context
Windows file extensions are case-insensitive and `.LNK` is common. The current implementation can fail to detect valid shortcuts.

### Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[74-94]
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[524-530]

### Suggested approach
- Update `getFileExtension` to return `extension.toLowerCase(Locale.ROOT)` (and adjust imports/tests accordingly), aligning with its Javadoc.
- Alternatively, change `isShortcutFile` to `filter(ext -> ext.equalsIgnoreCase("lnk"))` (but prefer central normalization in `getFileExtension`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java Outdated
@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Feb 8, 2026
@testlens-app

This comment has been minimized.

@Siedlerchr

Copy link
Copy Markdown
Member

There is another java library which apparently can parse this stuf https://github.com/DmitriiShamrikov/mslinks
But they don't have an up to date version published version on maven central argh

@koppor

koppor commented Feb 8, 2026

Copy link
Copy Markdown
Member

Note that resolving works at JabRef (!)

If I double click a .lnk file - JabRef opens. Thus "only" the drag and drop disallowance is wrong currently.

@koppor

koppor commented Feb 8, 2026

Copy link
Copy Markdown
Member

There is another java library which apparently can parse this stuf DmitriiShamrikov/mslinks But they don't have an up to date version published version on maven central argh

Who works on DmitriiShamrikov/mslinks#29 ?

@koppor

koppor commented Feb 8, 2026

Copy link
Copy Markdown
Member

We need the newver version, because of JDK11 compatibility - https://github.com/DmitriiShamrikov/mslinks/releases/tag/1.0.8

@koppor koppor marked this pull request as draft February 8, 2026 16:16
@faneeshh

faneeshh commented Feb 9, 2026

Copy link
Copy Markdown
Collaborator Author

Note that resolving works at JabRef (!)

If I double click a .lnk file - JabRef opens. Thus "only" the drag and drop disallowance is wrong currently.

I tested it by only allowing the .lnk extension. While the file is accepted by the UI, it currently results in an empty table because the Drag and Drop path doesn't seem to trigger the same resolution logic as double-clicking or the file picker. I am currently looking into how CommandLineProcessor or the main entry point handles .lnk files to see if I can reuse that existing resolution logic here without adding new dependencies like mslinks.

@faneeshh

faneeshh commented Feb 9, 2026

Copy link
Copy Markdown
Collaborator Author

@koppor I was able to resolve it by synchronizing the two seperate drag and drop code paths by integrating Windows shortcut resolution into the MainTable handlers. Previously dropping a .lnk file directly onto the table was bypassing the resolution logic in OpenDatabaseAction which resulted in "misc" entries. I think applying FileUtil : : resolveIfShortcut within both handleOnDragDroppedTable view and handleOnDragDropped in MainTable.java, and refining the resolution logic in FileUtil.java using mslinks.ShellLink now correctly resolves shortcuts. Let me know what you think!

@koppor

koppor commented Feb 11, 2026

Copy link
Copy Markdown
Member

recent mslink library available at org.jabref:mslinks:1.1.0-SNAPSHOT. See DmitriiShamrikov/mslinks#29 (comment) for details.

}

private boolean isAcceptedFile(Path path) {
return FileUtil.isBibFile(path) || FileUtil.isShortcutFile(path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condition wrong - i think, resolving should take place

Suggested change
return FileUtil.isBibFile(path) || FileUtil.isShortcutFile(path);
return FileUtil.isBibFile(FileUtils.resolveIfShortcut(path));

Comment thread CHANGELOG.md Outdated

### Fixed

- Allowed drag and drop of Windows shortcut (.lnk) files to open libraries [#15036] (https://github.com/JabRef/jabref/issues/15036)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space too much

import org.jabref.model.entry.LinkedFile;
import org.jabref.model.entry.field.StandardField;

import mslinks.ShellLink;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Siedlerchr Some dependency seems to already include mslinks :)

@github-actions

Copy link
Copy Markdown
Contributor

Your pull request conflicts with the target branch.

Please merge with your code. For a step-by-step guide to resolve merge conflicts, see https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line.

@koppor koppor marked this pull request as ready for review February 18, 2026 13:03
@github-actions

Copy link
Copy Markdown
Contributor

Do not mark a PR as ready-for-review while the CI is running. CI checks need to be completed and passed.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Support drag and drop of Windows shortcut (.lnk) files

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Added support for dragging and dropping Windows shortcut (.lnk) files
• Implemented shortcut resolution using mslinks library for target path detection
• Updated file acceptance logic in drag-and-drop handlers across UI components
• Resolves shortcuts before opening libraries to prevent file errors
Diagram
flowchart LR
  A["User drags .lnk file"] --> B["FrameDndHandler accepts .lnk files"]
  B --> C["OpenDatabaseAction resolves shortcut"]
  C --> D["FileUtil.resolveIfShortcut uses mslinks"]
  D --> E["Target .bib file opens in JabRef"]
  F["MainTable drag-drop also resolves shortcuts"] --> D
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java ✨ Enhancement +5/-1

Accept shortcut files in drag-and-drop handler

• Modified getBibFiles() to accept both .bib and .lnk files via new isAcceptedFile() method
• Added isAcceptedFile() helper method that checks for both bib files and shortcut files

jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java


2. jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java ✨ Enhancement +11/-4

Resolve shortcuts before opening database files

• Added import for Collectors and FileUtil
• Implemented shortcut resolution in openFiles() method before processing files
• Resolves all shortcuts to their target paths using FileUtil.resolveIfShortcut()
• Updated file iteration and processing to use resolved file list

jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java


3. jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java ✨ Enhancement +9/-2

Resolve shortcuts in MainTable drag-drop operations

• Added import for FileUtil
• Updated handleOnDragDropped() to resolve shortcuts when processing dropped files
• Updated handleOnDragDroppedTableView() to resolve shortcuts for import operations
• Applied FileUtil.resolveIfShortcut() in both drag-drop handlers

jabgui/src/main/java/org/jabref/gui/maintable/MainTable.java


View more (2)
4. jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java ✨ Enhancement +39/-0

Add shortcut detection and resolution utilities

• Added imports for mslinks.ShellLink and mslinks.ShellLinkException
• Implemented isShortcutFile() method to detect .lnk files by extension
• Implemented resolveIfShortcut() method that resolves Windows shortcuts to target paths
• Resolution only occurs on Windows systems and gracefully falls back to original path on failure
• Includes error handling and logging for shortcut resolution failures

jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java


5. CHANGELOG.md 📝 Documentation +1/-0

Document shortcut file drag-and-drop support

• Added entry documenting support for drag and drop of Windows shortcut files
• References issue #15036 in the Fixed section

CHANGELOG.md


Grey Divider

Qodo Logo

@github-actions

Copy link
Copy Markdown
Contributor

Do not mark a PR as ready-for-review if changes are required.
Address the changes first.

@koppor koppor marked this pull request as draft February 18, 2026 13:03
@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 510012a

Comment on lines +242 to +244
private boolean isAcceptedFile(Path path) {
return FileUtil.isBibFile(path) || FileUtil.isShortcutFile(path);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. .lnk accepted on non-windows platforms 🐞 Bug ✓ Correctness

isAcceptedFile() calls FileUtil.isShortcutFile() with no OS guard. On macOS/Linux a dropped
.lnk file passes the filter, but resolveIfShortcut() is a no-op there and returns the original
.lnk path, which is then fed to the BibTeX parser producing confusing parse errors.
Agent Prompt
## Issue description
`isAcceptedFile()` in `FrameDndHandler` accepts `.lnk` files on all operating systems because `FileUtil.isShortcutFile()` only checks the file extension. On non-Windows systems `resolveIfShortcut()` is a no-op and returns the original `.lnk` binary path, which is then parsed as BibTeX.

## Issue Context
- `FileUtil.isShortcutFile()` has no OS check (extension-only test).
- `FileUtil.resolveIfShortcut()` guards with `!OS.WINDOWS` and returns the original path immediately on non-Windows.
- `openTheFile()` only checks `Files.exists()`, so the `.lnk` binary reaches the parser.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/FrameDndHandler.java[242-244]

Change the method to:
```java
private boolean isAcceptedFile(Path path) {
    return FileUtil.isBibFile(path) || (OS.WINDOWS && FileUtil.isShortcutFile(path));
}
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +168 to +171
// Resolve any shortcuts to their targets
List<Path> resolvedFiles = filesToOpen.stream()
.map(FileUtil::resolveIfShortcut)
.collect(Collectors.toList());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. No .bib validation after shortcut resolution 🐞 Bug ✓ Correctness

After resolving a .lnk shortcut, the code never checks whether the resolved target is a .bib
file. A shortcut pointing to a .pdf, .docx, or any other file type is silently forwarded to
openTheFile() and parsed as a BibTeX database, producing confusing errors with no explanation.
Agent Prompt
## Issue description
After `resolveIfShortcut()` maps each path to its target, there is no check that the resolved target is actually a `.bib` file. A `.lnk` pointing to a `.pdf` or any other file type will be passed to `openTheFile()` and parsed as BibTeX.

## Issue Context
- The old code used `filter(FileUtil::isBibFile)` in `getBibFiles()` to guarantee only `.bib` files reached `openFiles()`.
- The new code removes that guarantee: `isAcceptedFile()` admits all `.lnk` files, and `openFiles()` does not re-validate after resolution.
- `openTheFile()` only checks `Files.exists()` (line 220), not the file extension.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]

Add a `.bib` filter after resolution:
```java
List<Path> resolvedFiles = filesToOpen.stream()
    .map(FileUtil::resolveIfShortcut)
    .filter(FileUtil::isBibFile)   // ← ensure resolved target is a .bib file
    .collect(Collectors.toList());
```

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +556 to +561
} catch (IOException | ShellLinkException e) {
LOGGER.warn("Could not resolve shortcut {}", path, e);
}

return path;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Failed resolution falls back to parsing .lnk binary 🐞 Bug ⛯ Reliability

When resolveIfShortcut() fails (exception thrown, or the shortcut target does not exist on disk),
it returns the original .lnk path. That path passes openTheFile()'s Files.exists() guard (the
.lnk file itself exists), so the binary .lnk content is fed to the BibTeX parser instead of
surfacing a clear "shortcut target not found" error. Broken/orphaned shortcuts are common in
real-world Windows usage.
Agent Prompt
## Issue description
When `resolveIfShortcut()` cannot resolve a shortcut (broken link, missing target, or parse exception), it returns the original `.lnk` path. This path passes `openTheFile()`'s `Files.exists()` check and the binary `.lnk` content is parsed as BibTeX, producing confusing errors instead of a clear failure message.

## Issue Context
- `resolveIfShortcut()` returns the original path on exception (line 556-560) and when the resolved target does not exist (line 552-554).
- The `.lnk` file itself exists on disk, so `openTheFile()`'s `Files.exists()` guard (line 220) does not filter it out.
- Broken shortcuts (target deleted or moved) are common in real-world Windows usage.

## Fix Focus Areas
- jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java[549-561]
- jabgui/src/main/java/org/jabref/gui/importer/actions/OpenDatabaseAction.java[168-171]

Preferred fix — add `filter(FileUtil::isBibFile)` after resolution in `openFiles()` (covers both this issue and Finding 2):
```java
List<Path> resolvedFiles = filesToOpen.stream()
    .map(FileUtil::resolveIfShortcut)
    .filter(FileUtil::isBibFile)
    .collect(Collectors.toList());
```
Alternatively, change `resolveIfShortcut()` to return `Optional<Path>` so callers can explicitly handle resolution failure.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@subhramit

Copy link
Copy Markdown
Member

Hi @faneeshh, can we get an update on this PR? There seems to be unresolved comments.

@faneeshh

Copy link
Copy Markdown
Collaborator Author

Ahh I think I accidentally pulled all upstream commits. Let me fix that.

@faneeshh faneeshh force-pushed the fix-for-issue-15036 branch from 9e70c9d to 6c9ade4 Compare March 16, 2026 20:28
@testlens-app

This comment has been minimized.

@github-actions github-actions Bot added status: no-bot-comments and removed status: changes-required Pull requests that are not yet complete labels Mar 16, 2026
@Siedlerchr

Copy link
Copy Markdown
Member

just do git fetch upstream && git merge upstream

@testlens-app

This comment has been minimized.

@testlens-app

This comment has been minimized.

@koppor koppor added status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers and removed status: no-bot-comments labels Mar 16, 2026
Comment thread jablib/src/main/java/org/jabref/logic/util/io/FileUtil.java Outdated
@testlens-app

This comment has been minimized.

Comment thread CHANGELOG.md Outdated
Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
@testlens-app

testlens-app Bot commented Mar 16, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 9090384
▶️ Tests: 10186 executed
⚪️ Checks: 54/54 completed


Learn more about TestLens at testlens.app.

@koppor koppor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the patience.

I tried it out. Works.

Will check the depencency later.

Comment on lines +435 to +448
@Test
void isShortcutFileReturnsTrueForPathEndingInLnk() {
assertTrue(FileUtil.isShortcutFile(Path.of("test.lnk")));
}

@Test
void isShortcutFileReturnsTrueForPathEndingInLnkCaseInsensitive() {
assertTrue(FileUtil.isShortcutFile(Path.of("test.LNK")));
}

@Test
void isShortcutFileReturnsFalseForPathEndingInBib() {
assertFalse(FileUtil.isShortcutFile(Path.of("test.bib")));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three could have been @ParamterizedTest with @ValueSource), but there should not be any more delay in getting this in.

}

@Test
@DisabledOnOs(value = org.junit.jupiter.api.condition.OS.WINDOWS, disabledReason = "Shortcut resolution only supported on Windows")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why the full import is needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OS.Windows of jabref and junit collide otherwise in this class

@koppor koppor enabled auto-merge March 16, 2026 22:44
@koppor koppor added this pull request to the merge queue Mar 16, 2026
@github-actions github-actions Bot added the status: to-be-merged PRs which are accepted and should go into the merge-queue. label Mar 16, 2026
Merged via the queue into JabRef:main with commit 93b5e19 Mar 16, 2026
54 checks passed
AnvitaPrasad pushed a commit to AnvitaPrasad/jabref that referenced this pull request Mar 18, 2026
* Allow drag and drop of Windows shortcut (.lnk) files Fixes JabRef#15036

* Specified the issue in ChangeLog

* fix(dnd): resolve .lnk shortcut targets in MainTable and FileUtil

* Resolved Windows shortcuts in MainTable drag and drop

* maint: revoled merge conflict in CHANGELOG

* Added the recommended fixes and validations

* Added tests

* Changelog grammar

* Apply suggestion from @koppor

* Apply suggestions from code review

Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>

---------

Co-authored-by: Subhramit Basu <subhramit.bb@live.in>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
FynnianB pushed a commit to FynnianB/jabref that referenced this pull request Mar 19, 2026
* Allow drag and drop of Windows shortcut (.lnk) files Fixes JabRef#15036

* Specified the issue in ChangeLog

* fix(dnd): resolve .lnk shortcut targets in MainTable and FileUtil

* Resolved Windows shortcuts in MainTable drag and drop

* maint: revoled merge conflict in CHANGELOG

* Added the recommended fixes and validations

* Added tests

* Changelog grammar

* Apply suggestion from @koppor

* Apply suggestions from code review

Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>

---------

Co-authored-by: Subhramit Basu <subhramit.bb@live.in>
Co-authored-by: Christoph <siedlerkiller@gmail.com>
Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
@koppor

koppor commented Mar 24, 2026

Copy link
Copy Markdown
Member

Does not work on latest main - I reopened the issue.

@koppor

koppor commented Mar 24, 2026

Copy link
Copy Markdown
Member

Update: Works -- if the shortcut points to an existing file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good first issue An issue intended for project-newcomers. Varies in difficulty. status: no-bot-comments status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers status: to-be-merged PRs which are accepted and should go into the merge-queue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Windows] Allow drag and drop of symblinks

4 participants