Skip to content

Stave sharing - Part 4#34036

Open
mike-spa wants to merge 7 commits into
musescore:mainfrom
mike-spa:STAVE_SHARING
Open

Stave sharing - Part 4#34036
mike-spa wants to merge 7 commits into
musescore:mainfrom
mike-spa:STAVE_SHARING

Conversation

@mike-spa

@mike-spa mike-spa commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Resolves: #34033
Resolves: #34039

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change updates shared voice and unison label formatting, adds new style settings and stave-sharing dialog controls for shared-on-staff numeral behavior, extends property and undo propagation to origin and shared items, and guards shared tuplet connection setup behind an assertion check.

Changes: systemheaderlayout.h/.cpp, stavesharinglayout.h/.cpp, styledef.h/.cpp, stavesharingpagemodel.h/.cpp, StaveSharingPage.qml, engravingobject.cpp, textbase.cpp

Sequence Diagram(s)

sequenceDiagram
  participant StaveSharingLayout
  participant SystemHeaderLayout
  participant EngravingObject
  participant TextBase

  StaveSharingLayout->>SystemHeaderLayout: formatSharedVoiceLabel(origin instruments, trailing-dot and hyphen style flags)
  SystemHeaderLayout-->>StaveSharingLayout: formatted shared label prefix
  StaveSharingLayout->>StaveSharingLayout: add restatement parentheses when needed

  EngravingObject->>EngravingObject: propagate changeProperty to originItems()
  EngravingObject->>EngravingObject: propagate changeProperty to sharedItem() when first origin
  TextBase->>TextBase: schedule ChangeTextProperties on originItems()
  TextBase->>TextBase: schedule ChangeTextProperties on sharedItem() when first origin
Loading

Related PRs: None identified from provided context.

Suggested labels: engraving, style, qml

Suggested reviewers: None identified from provided context.

Poem:
Shared labels now take a new road,
With origins and styles bestowed.
Undo, change, and tuplet link,
Each guarded step gives pause to think.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so the pull request summary is too sparse to convey the change clearly. Add a brief description of the stave-sharing changes and their purpose.
Title check ❓ Inconclusive The title is related to the stave-sharing changes, but it is too generic to explain the actual update. Rename it to describe the main change, such as unison/shared staff label formatting updates in stave sharing.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Linked repositories: Your configuration references 1 linked repositories, but your current plan allows 0. Analyzed ``, skipped musescore/muse_framework.git.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
src/engraving/rendering/score/systemheaderlayout.cpp (1)

1230-1279: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dead '\n' check in formatSharedVoiceLabel.

Line 1239's result.back() != '\n' guard is unreachable: every call site (the merged HORIZONTAL list, each VOICE-group call, and formatUnisonLabel's call) starts with a fresh empty String, and this function never inserts '\n' into result itself — that join happens in the caller (Line 1206). This appears to be a leftover from collapsing the old two-voice formatVoice(isFirstVoice) logic into a single helper.

♻️ Suggested simplification
-        if (!result.empty() && result.back() != '\n') {
+        if (!result.empty()) {
             result += '.';
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/engraving/rendering/score/systemheaderlayout.cpp` around lines 1230 -
1279, The `formatSharedVoiceLabel` helper still contains a dead `result.back()
!= '\n'` guard that can never trigger because the function always builds a fresh
`String` and never appends newlines itself. Remove that newline check and keep
the separator logic inside `SystemHeaderLayout::formatSharedVoiceLabel` focused
on joining labels with dots/hyphens only, since newline insertion is handled by
the caller.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/engraving/rendering/score/systemheaderlayout.cpp`:
- Around line 1230-1279: The `formatSharedVoiceLabel` helper still contains a
dead `result.back() != '\n'` guard that can never trigger because the function
always builds a fresh `String` and never appends newlines itself. Remove that
newline check and keep the separator logic inside
`SystemHeaderLayout::formatSharedVoiceLabel` focused on joining labels with
dots/hyphens only, since newline insertion is handled by the caller.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c2e8c465-f84a-493e-a309-19820d1096a2

📥 Commits

Reviewing files that changed from the base of the PR and between f9fe0fe and a2f9382.

📒 Files selected for processing (3)
  • src/engraving/rendering/score/stavesharinglayout.cpp
  • src/engraving/rendering/score/systemheaderlayout.cpp
  • src/engraving/rendering/score/systemheaderlayout.h

@mike-spa mike-spa changed the title Format on-staff label the same way as margin labels Stave sharing - Part 4 Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/engraving/dom/textbase.cpp`:
- Around line 3390-3397: The shared-text undo path in TextBase::setProperty is
recording ChangeTextProperties on this->score() even when the cursor belongs to
a different origin/shared item. Update the loop over originItems() and the
sharedItem() propagation so each undo command is submitted through the target
item’s owning score, matching the linkedText->score() behavior and keeping the
undo transaction attached to the edited object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a56e4de5-ddba-4e95-a4a4-4301e8fc3d54

📥 Commits

Reviewing files that changed from the base of the PR and between a2f9382 and de6dd2d.

📒 Files selected for processing (3)
  • src/engraving/dom/engravingobject.cpp
  • src/engraving/dom/textbase.cpp
  • src/engraving/rendering/score/stavesharinglayout.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/engraving/rendering/score/stavesharinglayout.cpp

Comment on lines +3390 to +3397
for (EngravingItem* originItem : originItems()) {
// This is a shared item: propagate to all origin items
score()->undo(new ChangeTextProperties(toTextBase(originItem)->cursor(), id, v, ps));
}
if (EngravingItem* sharedEl = sharedItem(); sharedEl && sharedEl->originItems().front() == this) {
// This is the first origin item of the shared item: propagate to shared item
score()->undo(new ChangeTextProperties(toTextBase(sharedEl)->cursor(), id, v, ps));
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use the target item's score for shared text undo commands.

The linked-object path above uses linkedText->score(), but this new shared-item path records undo commands on this->score() while targeting another item's cursor. Route each command through the target item’s score to keep the undo transaction attached to the edited object’s owning score.

Proposed fix
     for (EngravingItem* originItem : originItems()) {
         // This is a shared item: propagate to all origin items
-        score()->undo(new ChangeTextProperties(toTextBase(originItem)->cursor(), id, v, ps));
+        originItem->score()->undo(new ChangeTextProperties(toTextBase(originItem)->cursor(), id, v, ps));
     }
     if (EngravingItem* sharedEl = sharedItem(); sharedEl && sharedEl->originItems().front() == this) {
         // This is the first origin item of the shared item: propagate to shared item
-        score()->undo(new ChangeTextProperties(toTextBase(sharedEl)->cursor(), id, v, ps));
+        sharedEl->score()->undo(new ChangeTextProperties(toTextBase(sharedEl)->cursor(), id, v, ps));
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (EngravingItem* originItem : originItems()) {
// This is a shared item: propagate to all origin items
score()->undo(new ChangeTextProperties(toTextBase(originItem)->cursor(), id, v, ps));
}
if (EngravingItem* sharedEl = sharedItem(); sharedEl && sharedEl->originItems().front() == this) {
// This is the first origin item of the shared item: propagate to shared item
score()->undo(new ChangeTextProperties(toTextBase(sharedEl)->cursor(), id, v, ps));
}
for (EngravingItem* originItem : originItems()) {
// This is a shared item: propagate to all origin items
originItem->score()->undo(new ChangeTextProperties(toTextBase(originItem)->cursor(), id, v, ps));
}
if (EngravingItem* sharedEl = sharedItem(); sharedEl && sharedEl->originItems().front() == this) {
// This is the first origin item of the shared item: propagate to shared item
sharedEl->score()->undo(new ChangeTextProperties(toTextBase(sharedEl)->cursor(), id, v, ps));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/engraving/dom/textbase.cpp` around lines 3390 - 3397, The shared-text
undo path in TextBase::setProperty is recording ChangeTextProperties on
this->score() even when the cursor belongs to a different origin/shared item.
Update the loop over originItems() and the sharedItem() propagation so each undo
command is submitted through the target item’s owning score, matching the
linkedText->score() behavior and keeping the undo transaction attached to the
edited object.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
src/notationscene/qml/MuseScore/NotationScene/styledialog/StaveSharingPage.qml (1)

72-76: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: inconsistent checkbox toggle idiom.

Line 75 uses !staveSharingModel.allowVoiceCrossing.value while line 141 uses !checked for the same kind of fully-controlled CheckBox. Both are functionally equivalent here, but using !checked consistently (as in line 141) is the established idiom for this component in the codebase.

♻️ Optional consistency fix
                     CheckBox {
                         text: qsTrc("notation/editstyle/stavesharing", "Allow voice crossing")
                         checked: staveSharingModel.allowVoiceCrossing.value === true
-                        onClicked: staveSharingModel.allowVoiceCrossing.value = !staveSharingModel.allowVoiceCrossing.value
+                        onClicked: staveSharingModel.allowVoiceCrossing.value = !checked
                     }

Also applies to: 138-142

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/notationscene/qml/MuseScore/NotationScene/styledialog/StaveSharingPage.qml`
around lines 72 - 76, The fully controlled CheckBox in StaveSharingPage.qml uses
an inconsistent toggle pattern for “Allow voice crossing”; update the onClicked
handler in the CheckBox tied to staveSharingModel.allowVoiceCrossing so it
follows the same established idiom as the other CheckBox in this component. Keep
the checked binding as-is, but change the toggle logic to use the current
checked state rather than directly negating the model value, matching the
pattern used by the other control in StaveSharingPage.qml.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/notationscene/qml/MuseScore/NotationScene/styledialog/StaveSharingPage.qml`:
- Around line 72-76: The fully controlled CheckBox in StaveSharingPage.qml uses
an inconsistent toggle pattern for “Allow voice crossing”; update the onClicked
handler in the CheckBox tied to staveSharingModel.allowVoiceCrossing so it
follows the same established idiom as the other CheckBox in this component. Keep
the checked binding as-is, but change the toggle logic to use the current
checked state rather than directly negating the model value, matching the
pattern used by the other control in StaveSharingPage.qml.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4575c34b-1078-4bab-b447-73d46fb6ef62

📥 Commits

Reviewing files that changed from the base of the PR and between de6dd2d and 48bbab9.

📒 Files selected for processing (10)
  • src/engraving/dom/engravingobject.cpp
  • src/engraving/dom/textbase.cpp
  • src/engraving/rendering/score/stavesharinglayout.cpp
  • src/engraving/rendering/score/systemheaderlayout.cpp
  • src/engraving/rendering/score/systemheaderlayout.h
  • src/engraving/style/styledef.cpp
  • src/engraving/style/styledef.h
  • src/notationscene/qml/MuseScore/NotationScene/styledialog/StaveSharingPage.qml
  • src/notationscene/qml/MuseScore/NotationScene/styledialog/stavesharingpagemodel.cpp
  • src/notationscene/qml/MuseScore/NotationScene/styledialog/stavesharingpagemodel.h
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/engraving/rendering/score/systemheaderlayout.h
  • src/engraving/dom/engravingobject.cpp
  • src/engraving/rendering/score/stavesharinglayout.cpp
  • src/engraving/dom/textbase.cpp
  • src/engraving/rendering/score/systemheaderlayout.cpp

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

Labels

None yet

Projects

None yet

2 participants