Skip to content

fix visual snap of side pane on startup#15553

Open
pgrigolli wants to merge 9 commits intoJabRef:mainfrom
pgrigolli:fix-for-issue-15394
Open

fix visual snap of side pane on startup#15553
pgrigolli wants to merge 9 commits intoJabRef:mainfrom
pgrigolli:fix-for-issue-15394

Conversation

@pgrigolli
Copy link
Copy Markdown

@pgrigolli pgrigolli commented Apr 15, 2026

Related issues and pull requests

Closes #15394

PR Description

When JabRef starts, the side pane was briefly rendered in the wrong position
before snapping to the correct width previously set by the user. The root cause
was that updateHorizontalDividerPosition() was called before the layout was ready,
causing the divider position to not be applied correctly. This was fixed by hiding
the horizontal split pane while the divider position is being applied, and showing
it again only after the correct position has been set, preventing the snap from
being visible to the user.

Steps to test

  1. Open JabRef
  2. Make sure the side pane is visible (Groups or Web Search panel)
  3. Drag the side pane border to adjust its width — try both small and large widths (including wider than half the screen)
  4. Close JabRef
  5. Reopen JabRef and verify that the side pane opens directly at the correct width, without any visible snapping behavior
  6. Repeat steps 3-5 multiple times with different widths to confirm consistency

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 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

Video of the changes working (on Windows 11, developer version)
https://github.com/user-attachments/assets/782147b0-ded8-4b13-ad5c-527f67f63211

I couldn't test it on MacOS, but I tested on Linux (Debian 12) and it wasn't happening there!
Since the issue was first addressed on Windows, it should work now!

Library Entry
JabRefLibraryEntry

@jabref-machine
Copy link
Copy Markdown
Collaborator

Note that your PR will not be reviewed/accepted until you have gone through the mandatory checks in the description and marked each of them them exactly in the format of - [x] (done), - [ ] (yet to be done) or - [/] (not applicable). Please adhere to our pull request template.

@pgrigolli pgrigolli marked this pull request as ready for review April 15, 2026 02:36
@koppor koppor marked this pull request as draft April 15, 2026 02:36
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Fix visual snap of side pane on startup

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Hide side pane during divider position initialization to prevent visual snap
• Apply divider position after stage is fully shown using Platform.runLater
• Add listener to update divider position when main stage becomes visible
• Update changelog to document the side pane snap fix
Diagram
flowchart LR
  A["Side pane added to split"] -- "Hide split pane" --> B["Platform.runLater"]
  B -- "Update divider position" --> C["Show split pane"]
  D["Main stage showing"] -- "Listener triggered" --> E["Update divider position"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java 🐞 Bug fix +11/-1

Defer divider position update and hide pane during initialization

• Hide horizontalSplit before adding side pane and updating divider position
• Defer updateHorizontalDividerPosition() call using Platform.runLater() to ensure layout is
 ready
• Show horizontalSplit after divider position is applied
• Add listener to mainStage.showingProperty() to update divider position when stage becomes
 visible

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


2. CHANGELOG.md 📝 Documentation +2/-0

Document side pane snap fix in changelog

• Add entry documenting the removal of side panel snap on startup
• Reference issue #15394 in the changelog entry

CHANGELOG.md


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 15, 2026

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (3)   📎 Requirement gaps (0)
🐞\ ☼ Reliability (1) ⚙ Maintainability (1)
📘\ ☼ Reliability (1) ⚙ Maintainability (2)

Grey Divider


Action required

1. CHANGELOG.md adds blank line 📘
Description
An extra blank line was added before the new changelog bullet, which violates the requirement to
avoid introducing extra blank lines. This can lead to inconsistent changelog formatting.
Code

CHANGELOG.md[14]

+
Evidence
PR Compliance ID 28 forbids adding extra blank lines in CHANGELOG.md. The diff adds a standalone
blank line at line 14.

AGENTS.md
CHANGELOG.md[14-14]

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

## Issue description
`CHANGELOG.md` introduces an extra blank line before the new entry, violating formatting requirements.

## Issue Context
The changelog should remain consistently formatted without extra blank lines.

## Fix Focus Areas
- CHANGELOG.md[14-14]

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


2. Leaked divider subscriptions 🐞
Description
initBindings() adds a mainStage.showingProperty listener that calls
updateHorizontalDividerPosition(), but JabRefGUI.onShowing() already calls it; because
updateHorizontalDividerPosition() overwrites horizontalDividerSubscription without unsubscribing
the previous subscription, repeated window show cycles will leak listeners and duplicate preference
updates.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R414-418]

+        mainStage.showingProperty().addListener((obs, wasShowing, isShowing) -> {
+            if (isShowing) {
+                updateHorizontalDividerPosition();
+            }
+        });
Evidence
The new showing-property listener invokes updateHorizontalDividerPosition() whenever the stage
becomes showing. Separately, JabRefGUI.onShowing already schedules
mainFrame.updateHorizontalDividerPosition(). The divider update method creates a new EasyBind
subscription and assigns it to horizontalDividerSubscription without unsubscribing any existing
subscription, so multiple calls accumulate subscriptions and side effects.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-319]

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

### Issue description
`updateHorizontalDividerPosition()` installs an EasyBind listener each time it runs, but it does not unsubscribe any prior listener. This PR adds an additional call site (`mainStage.showingProperty` listener), while `JabRefGUI.onShowing()` already calls the method, so subscriptions can stack up across show/hide cycles.

### Issue Context
- `JabRefGUI.onShowing()` already calls `mainFrame.updateHorizontalDividerPosition()`.
- `updateHorizontalDividerPosition()` assigns `horizontalDividerSubscription = ...listenToValues(...)` without cleanup.

### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-320]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
- jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]

### Suggested fix approach
- Prefer a single invocation path (remove the newly-added `showingProperty` listener, since `JabRefGUI.onShowing()` already handles it), **or**
- Make `updateHorizontalDividerPosition()` idempotent by unsubscribing an existing `horizontalDividerSubscription` before creating a new one (and consider doing the same for vertical for consistency).

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



Remediation recommended

3. Informal changelog entry text 📘
Description
The new changelog entry uses informal/awkward phrasing (e.g., a little snap, `when one opened
JabRef`) and is not as precise/professional as required for release notes. This reduces clarity for
end users reading the changelog.
Code

CHANGELOG.md[15]

+- We removed a little snap that used to happen with the side panel when one opened JabRef after changing the side panel's default position [#15394](https://github.com/JabRef/jabref/issues/15394)
Evidence
PR Compliance ID 36 requires professional, precise user-facing release note wording. The added
bullet uses informal language and awkward phrasing.

CHANGELOG.md[15-15]
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 added changelog bullet is informal/awkwardly phrased and should be rewritten to be professional and precise.

## Issue Context
Release notes should be easily understood by end users and consistently written.

## Fix Focus Areas
- CHANGELOG.md[15-15]

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


4. UI change lacks test 📘
Description
The PR changes side pane divider behavior/timing in JabRefFrame but does not add or update tests
in the provided diff. This risks regressions of the startup layout behavior across platforms.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
                horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
PR Compliance ID 22 requires tests for behavior changes. The diff modifies UI behavior using
Platform.runLater(...) and a visibility toggle without any accompanying test changes shown in the
PR diff.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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 side pane startup/layout behavior was changed, but no tests were added/updated in the provided diff to prevent regressions.

## Issue Context
This change is timing-dependent (`Platform.runLater`, stage showing listener) and can regress across platforms/window states.

## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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


5. SplitPane hidden on toggle 🐞
Description
updateSidePane() now calls horizontalSplit.setVisible(false) while adding the side pane, which
hides the entire main content area whenever side panes become visible (not just on startup). Since
SidePane.updateView() rebuilds children on visibility toggles, enabling a side pane at runtime
will blank the whole UI for at least one JavaFX pulse.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
                horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
JabRefFrame listens to sidePane.getChildren() changes and calls updateSidePane().
SidePane.updateView() clears and re-adds children whenever the set of visible side pane components
changes. When a user toggles side panes from none->some, updateSidePane() runs and explicitly
hides horizontalSplit until the deferred runnable executes, meaning the whole center content
disappears temporarily.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]

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

### Issue description
To avoid the divider-position snap, the code hides `horizontalSplit`, which blanks the entire main UI when a side pane is enabled at runtime.

### Issue Context
`SidePane.updateView()` clears/rebuilds children when visible side pane components change, and `JabRefFrame` reacts to `sidePane.getChildren()` changes by calling `updateSidePane()`.

### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
- jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]

### Suggested fix approach
- Avoid hiding the whole `horizontalSplit`. Instead, hide only the newly-added `sidePane` (e.g., `sidePane.setVisible(false)` before adding, then show it after setting divider position), or use opacity on the side pane.
- Keep divider positioning deferred (`Platform.runLater`) if needed, but restore visibility without blanking the center content.

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread CHANGELOG.md Outdated
Comment on lines +414 to +418
mainStage.showingProperty().addListener((obs, wasShowing, isShowing) -> {
if (isShowing) {
updateHorizontalDividerPosition();
}
});
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. Leaked divider subscriptions 🐞 Bug ☼ Reliability

initBindings() adds a mainStage.showingProperty listener that calls
updateHorizontalDividerPosition(), but JabRefGUI.onShowing() already calls it; because
updateHorizontalDividerPosition() overwrites horizontalDividerSubscription without unsubscribing
the previous subscription, repeated window show cycles will leak listeners and duplicate preference
updates.
Agent Prompt
### Issue description
`updateHorizontalDividerPosition()` installs an EasyBind listener each time it runs, but it does not unsubscribe any prior listener. This PR adds an additional call site (`mainStage.showingProperty` listener), while `JabRefGUI.onShowing()` already calls the method, so subscriptions can stack up across show/hide cycles.

### Issue Context
- `JabRefGUI.onShowing()` already calls `mainFrame.updateHorizontalDividerPosition()`.
- `updateHorizontalDividerPosition()` assigns `horizontalDividerSubscription = ...listenToValues(...)` without cleanup.

### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-320]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
- jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]

### Suggested fix approach
- Prefer a single invocation path (remove the newly-added `showingProperty` listener, since `JabRefGUI.onShowing()` already handles it), **or**
- Make `updateHorizontalDividerPosition()` idempotent by unsubscribing an existing `horizontalDividerSubscription` before creating a new one (and consider doing the same for vertical for consistency).

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

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.

@pgrigolli needs to be addressed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hey, turns out it was just dead code that I forgot to remove from one try to another. Removed on the last commit!

Comment thread CHANGELOG.md Outdated
@pgrigolli
Copy link
Copy Markdown
Author

Idk why these tests aren't passing. What should I do?

@calixtus
Copy link
Copy Markdown
Member

We are looking into it, please be patient. Maybe something with our CI pipeline.

@subhramit
Copy link
Copy Markdown
Member

@pgrigolli should be fine now.

@pgrigolli
Copy link
Copy Markdown
Author

@pgrigolli should be fine now.

Nice, thanks! What was wrong?

@subhramit
Copy link
Copy Markdown
Member

Nice, thanks! What was wrong?

We had a faulty Windows-specific test which was fixed in one of the recent PRs.

@pgrigolli pgrigolli marked this pull request as ready for review April 16, 2026 22:50
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Fix side pane visual snap on startup

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Hide side pane during divider position initialization to prevent visual snap
• Use Platform.runLater() to apply divider position after layout is ready
• Show side pane only after correct position has been set
• Updated CHANGELOG.md with fix description
Diagram
flowchart LR
  A["Side pane added to split"] --> B["Hide horizontal split pane"]
  B --> C["Schedule divider position update"]
  C --> D["Apply correct divider position"]
  D --> E["Show horizontal split pane"]
  E --> F["Side pane displays at correct width"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java 🐞 Bug fix +5/-1

Hide side pane during divider position initialization

• Hide horizontalSplit pane before adding side pane to prevent visual snap
• Wrap updateHorizontalDividerPosition() call in Platform.runLater() to ensure layout is ready
• Show horizontalSplit pane after divider position has been applied
• Ensures divider position is set before the UI becomes visible to the user

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


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

Document side pane divider position fix

• Added entry documenting the fix for side pane divider position glitch on startup
• References issue #15394 with link to GitHub issue

CHANGELOG.md


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 16, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

1. CHANGELOG.md adds blank line 📘 Rule violation ⚙ Maintainability
Description
An extra blank line was added before the new changelog bullet, which violates the requirement to
avoid introducing extra blank lines. This can lead to inconsistent changelog formatting.
Code

CHANGELOG.md[14]

+
Evidence
PR Compliance ID 28 forbids adding extra blank lines in CHANGELOG.md. The diff adds a standalone
blank line at line 14.

AGENTS.md
CHANGELOG.md[14-14]

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

## Issue description
`CHANGELOG.md` introduces an extra blank line before the new entry, violating formatting requirements.
## Issue Context
The changelog should remain consistently formatted without extra blank lines.
## Fix Focus Areas
- CHANGELOG.md[14-14]

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


2. Leaked divider subscriptions 🐞 Bug ☼ Reliability
Description
initBindings() adds a mainStage.showingProperty listener that calls
updateHorizontalDividerPosition(), but JabRefGUI.onShowing() already calls it; because
updateHorizontalDividerPosition() overwrites horizontalDividerSubscription without unsubscribing
the previous subscription, repeated window show cycles will leak listeners and duplicate preference
updates.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R414-418]

+        mainStage.showingProperty().addListener((obs, wasShowing, isShowing) -> {
+            if (isShowing) {
+                updateHorizontalDividerPosition();
+            }
+        });
Evidence
The new showing-property listener invokes updateHorizontalDividerPosition() whenever the stage
becomes showing. Separately, JabRefGUI.onShowing already schedules
mainFrame.updateHorizontalDividerPosition(). The divider update method creates a new EasyBind
subscription and assigns it to horizontalDividerSubscription without unsubscribing any existing
subscription, so multiple calls accumulate subscriptions and side effects.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-319]

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

## Issue description
`updateHorizontalDividerPosition()` installs an EasyBind listener each time it runs, but it does not unsubscribe any prior listener. This PR adds an additional call site (`mainStage.showingProperty` listener), while `JabRefGUI.onShowing()` already calls the method, so subscriptions can stack up across show/hide cycles.
### Issue Context
- `JabRefGUI.onShowing()` already calls `mainFrame.updateHorizontalDividerPosition()`.
- `updateHorizontalDividerPosition()` assigns `horizontalDividerSubscription = ...listenToValues(...)` without cleanup.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-320]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
- jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]
### Suggested fix approach
- Prefer a single invocation path (remove the newly-added `showingProperty` listener, since `JabRefGUI.onShowing()` already handles it), **or**
- Make `updateHorizontalDividerPosition()` idempotent by unsubscribing an existing `horizontalDividerSubscription` before creating a new one (and consider doing the same for vertical for consistency).

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



Remediation recommended

3. Informal changelog entry text 📘 Rule violation ⚙ Maintainability
Description
The new changelog entry uses informal/awkward phrasing (e.g., a little snap, `when one opened
JabRef`) and is not as precise/professional as required for release notes. This reduces clarity for
end users reading the changelog.
Code

CHANGELOG.md[15]

+- We removed a little snap that used to happen with the side panel when one opened JabRef after changing the side panel's default position [#15394](https://github.com/JabRef/jabref/issues/15394)
Evidence
PR Compliance ID 36 requires professional, precise user-facing release note wording. The added
bullet uses informal language and awkward phrasing.

CHANGELOG.md[15-15]
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 added changelog bullet is informal/awkwardly phrased and should be rewritten to be professional and precise.
## Issue Context
Release notes should be easily understood by end users and consistently written.
## Fix Focus Areas
- CHANGELOG.md[15-15]

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


4. UI change lacks test 📘 Rule violation ☼ Reliability
Description
The PR changes side pane divider behavior/timing in JabRefFrame but does not add or update tests
in the provided diff. This risks regressions of the startup layout behavior across platforms.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
               horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
PR Compliance ID 22 requires tests for behavior changes. The diff modifies UI behavior using
Platform.runLater(...) and a visibility toggle without any accompanying test changes shown in the
PR diff.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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 side pane startup/layout behavior was changed, but no tests were added/updated in the provided diff to prevent regressions.
## Issue Context
This change is timing-dependent (`Platform.runLater`, stage showing listener) and can regress across platforms/window states.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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


5. SplitPane hidden on toggle 🐞 Bug ⚙ Maintainability
Description
updateSidePane() now calls horizontalSplit.setVisible(false) while adding the side pane, which
hides the entire main content area whenever side panes become visible (not just on startup). Since
SidePane.updateView() rebuilds children on visibility toggles, enabling a side pane at runtime
will blank the whole UI for at least one JavaFX pulse.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
               horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
JabRefFrame listens to sidePane.getChildren() changes and calls updateSidePane().
SidePane.updateView() clears and re-adds children whenever the set of visible side pane components
changes. When a user toggles side panes from none->some, updateSidePane() runs and explicitly
hides horizontalSplit until the deferred runnable executes, meaning the whole center content
disappears temporarily.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]

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

## Issue description
To avoid the divider-position snap, the code hides `horizontalSplit`, which blanks the entire main UI when a side pane is enabled at runtime.
### Issue Context
`SidePane.updateView()` clears/rebuilds children when visible side pane components change, and `JabRefFrame` reacts to `sidePane.getChildren()` changes by calling `updateSidePane()`.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
- jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]
### Suggested fix approach
- Avoid hiding the whole `horizontalSplit`. Instead, hide only the newly-added `sidePane` (e.g., `sidePane.setVisible(false)` before adding, then show it after setting divider position), or use opacity on the side pane.
- Keep divider positioning deferred (`Platform.runLater`) if needed, but restore visibility without blanking the center content.

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

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 April 16, 2026 22:50
@subhramit
Copy link
Copy Markdown
Member

subhramit commented Apr 16, 2026

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

@koppor this action seems flaky
Edit - Nvm, seems like it was marked RFR before the tests completed. Maybe it should run only when a test actually fails?

@subhramit subhramit marked this pull request as ready for review April 16, 2026 22:57
@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Fix side pane snap on startup by deferring position update

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fixes visual snap of side pane on startup by hiding it during initialization
• Applies divider position after layout is ready using Platform.runLater()
• Prevents incorrect positioning before showing the pane to user
• Updates changelog to document the fix
Diagram
flowchart LR
  A["Side pane added to split"] -- "Hide split pane" --> B["Defer position update"]
  B -- "Apply divider position" --> C["Show split pane"]
  C -- "User sees correct position" --> D["No visual snap"]
Loading

Grey Divider

File Changes

1. jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java 🐞 Bug fix +5/-1

Defer divider position update until layout ready

• Hides horizontalSplit pane before adding side pane to prevent visual snap
• Defers updateHorizontalDividerPosition() call using Platform.runLater() to ensure layout is
 ready
• Shows horizontalSplit pane again after divider position is applied
• Removes synchronous divider position update that occurred before layout initialization

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


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

Document side pane divider position fix

• Adds entry documenting the fix for side pane divider position glitch on startup
• References issue #15394 in the changelog entry
• Placed in the "Added" section of the changelog

CHANGELOG.md


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 16, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (4) 📎 Requirement gaps (0)

Grey Divider


Action required

1. CHANGELOG.md adds blank line 📘 Rule violation ⚙ Maintainability
Description
An extra blank line was added before the new changelog bullet, which violates the requirement to
avoid introducing extra blank lines. This can lead to inconsistent changelog formatting.
Code

CHANGELOG.md[14]

+
Evidence
PR Compliance ID 28 forbids adding extra blank lines in CHANGELOG.md. The diff adds a standalone
blank line at line 14.

AGENTS.md
CHANGELOG.md[14-14]

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

## Issue description
`CHANGELOG.md` introduces an extra blank line before the new entry, violating formatting requirements.
## Issue Context
The changelog should remain consistently formatted without extra blank lines.
## Fix Focus Areas
- CHANGELOG.md[14-14]

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


2. Leaked divider subscriptions 🐞 Bug ☼ Reliability
Description
initBindings() adds a mainStage.showingProperty listener that calls
updateHorizontalDividerPosition(), but JabRefGUI.onShowing() already calls it; because
updateHorizontalDividerPosition() overwrites horizontalDividerSubscription without unsubscribing
the previous subscription, repeated window show cycles will leak listeners and duplicate preference
updates.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R414-418]

+        mainStage.showingProperty().addListener((obs, wasShowing, isShowing) -> {
+            if (isShowing) {
+                updateHorizontalDividerPosition();
+            }
+        });
Evidence
The new showing-property listener invokes updateHorizontalDividerPosition() whenever the stage
becomes showing. Separately, JabRefGUI.onShowing already schedules
mainFrame.updateHorizontalDividerPosition(). The divider update method creates a new EasyBind
subscription and assigns it to horizontalDividerSubscription without unsubscribing any existing
subscription, so multiple calls accumulate subscriptions and side effects.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-319]

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

## Issue description
`updateHorizontalDividerPosition()` installs an EasyBind listener each time it runs, but it does not unsubscribe any prior listener. This PR adds an additional call site (`mainStage.showingProperty` listener), while `JabRefGUI.onShowing()` already calls the method, so subscriptions can stack up across show/hide cycles.
### Issue Context
- `JabRefGUI.onShowing()` already calls `mainFrame.updateHorizontalDividerPosition()`.
- `updateHorizontalDividerPosition()` assigns `horizontalDividerSubscription = ...listenToValues(...)` without cleanup.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[311-320]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[411-418]
- jabgui/src/main/java/org/jabref/gui/JabRefGUI.java[357-361]
### Suggested fix approach
- Prefer a single invocation path (remove the newly-added `showingProperty` listener, since `JabRefGUI.onShowing()` already handles it), **or**
- Make `updateHorizontalDividerPosition()` idempotent by unsubscribing an existing `horizontalDividerSubscription` before creating a new one (and consider doing the same for vertical for consistency).

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



Remediation recommended

3. Changelog uses sidepane typo 📘 Rule violation ⚙ Maintainability ⭐ New
Description
The new CHANGELOG entry uses the misspelling sidepane and includes technical wording (`divider
position`) that is less end-user oriented. This can reduce professionalism and readability of
release notes for users.
Code

CHANGELOG.md[14]

+- We fixed a glitch with the sidepane divider position on startup. [#15394](https://github.com/JabRef/jabref/issues/15394)
Evidence
PR Compliance ID 34 requires professional, typo-free user-facing documentation, and PR Compliance ID
30 requires CHANGELOG entries to be end-user oriented. The added line contains sidepane
(typo/inconsistent terminology) and uses UI-implementation jargon (divider position).

AGENTS.md
CHANGELOG.md[14-14]
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 added `CHANGELOG.md` entry contains a typo (`sidepane`) and uses technical wording (`divider position`) that is not ideal for end users.

## Issue Context
Changelog entries should be professional and readable by average users.

## Fix Focus Areas
- CHANGELOG.md[14-14]

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


4. Informal changelog entry text 📘 Rule violation ⚙ Maintainability
Description
The new changelog entry uses informal/awkward phrasing (e.g., a little snap, `when one opened
JabRef`) and is not as precise/professional as required for release notes. This reduces clarity for
end users reading the changelog.
Code

CHANGELOG.md[15]

+- We removed a little snap that used to happen with the side panel when one opened JabRef after changing the side panel's default position [#15394](https://github.com/JabRef/jabref/issues/15394)
Evidence
PR Compliance ID 36 requires professional, precise user-facing release note wording. The added
bullet uses informal language and awkward phrasing.

CHANGELOG.md[15-15]
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 added changelog bullet is informal/awkwardly phrased and should be rewritten to be professional and precise.
## Issue Context
Release notes should be easily understood by end users and consistently written.
## Fix Focus Areas
- CHANGELOG.md[15-15]

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


5. UI change lacks test 📘 Rule violation ☼ Reliability
Description
The PR changes side pane divider behavior/timing in JabRefFrame but does not add or update tests
in the provided diff. This risks regressions of the startup layout behavior across platforms.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
               horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
PR Compliance ID 22 requires tests for behavior changes. The diff modifies UI behavior using
Platform.runLater(...) and a visibility toggle without any accompanying test changes shown in the
PR diff.

AGENTS.md
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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 side pane startup/layout behavior was changed, but no tests were added/updated in the provided diff to prevent regressions.
## Issue Context
This change is timing-dependent (`Platform.runLater`, stage showing listener) and can regress across platforms/window states.
## Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[287-292]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[414-418]

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


View more (1)
6. SplitPane hidden on toggle 🐞 Bug ⚙ Maintainability
Description
updateSidePane() now calls horizontalSplit.setVisible(false) while adding the side pane, which
hides the entire main content area whenever side panes become visible (not just on startup). Since
SidePane.updateView() rebuilds children on visibility toggles, enabling a side pane at runtime
will blank the whole UI for at least one JavaFX pulse.
Code

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[R287-292]

+                horizontalSplit.setVisible(false);
               horizontalSplit.getItems().addFirst(sidePane);
-                updateHorizontalDividerPosition();
+                Platform.runLater(() -> {
+                    updateHorizontalDividerPosition();
+                    horizontalSplit.setVisible(true);
+                });
Evidence
JabRefFrame listens to sidePane.getChildren() changes and calls updateSidePane().
SidePane.updateView() clears and re-adds children whenever the set of visible side pane components
changes. When a user toggles side panes from none->some, updateSidePane() runs and explicitly
hides horizontalSplit until the deferred runnable executes, meaning the whole center content
disappears temporarily.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]

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

## Issue description
To avoid the divider-position snap, the code hides `horizontalSplit`, which blanks the entire main UI when a side pane is enabled at runtime.
### Issue Context
`SidePane.updateView()` clears/rebuilds children when visible side pane components change, and `JabRefFrame` reacts to `sidePane.getChildren()` changes by calling `updateSidePane()`.
### Fix Focus Areas
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[279-295]
- jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java[269-276]
- jabgui/src/main/java/org/jabref/gui/sidepane/SidePane.java[67-73]
### Suggested fix approach
- Avoid hiding the whole `horizontalSplit`. Instead, hide only the newly-added `sidePane` (e.g., `sidePane.setVisible(false)` before adding, then show it after setting divider position), or use opacity on the side pane.
- Keep divider positioning deferred (`Platform.runLater`) if needed, but restore visibility without blanking the center content.

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

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

Labels

component: ui status: changes-required Pull requests that are not yet complete

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix sidepane opening in the middle of the screen then snapping to configured width

4 participants