Merge pull request #15988 from cbjeukendrup/corruption_check_parts

Also check part scores for corruptions
This commit is contained in:
Elnur Ismailzada 2023-02-13 08:47:28 +02:00 committed by GitHub
commit 695701af3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 30 deletions

View file

@ -23,9 +23,9 @@
#include "chordrest.h"
#include "factory.h"
#include "keysig.h"
#include "masterscore.h"
#include "measure.h"
#include "rest.h"
#include "score.h"
#include "segment.h"
#include "staff.h"
#include "tuplet.h"
@ -106,17 +106,51 @@ void Score::checkScore()
/// Check that voices > 1 contains less than measure duration
//---------------------------------------------------------
Ret Score::sanityCheck()
Ret MasterScore::sanityCheck()
{
std::string accumulatedErrors;
for (Score* score : scoreList()) {
Ret ret = score->sanityCheckLocal();
if (ret) {
// everything is fine in this part, let's continue
continue;
}
if (!accumulatedErrors.empty()) {
accumulatedErrors += "\n";
}
accumulatedErrors += ret.text();
}
if (accumulatedErrors.empty()) {
return make_ok();
}
return Ret(static_cast<int>(Err::FileCorrupted), accumulatedErrors);
}
Ret Score::sanityCheckLocal()
{
StringList errors;
int mNumber = 1;
auto excerptInfo = [this]() {
if (isMaster()) {
return mtrc("engraving", "Full score");
}
//: %1 is the name of a part score.
return mtrc("engraving", "Part score: %1").arg(name());
};
for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
Fraction mLen = m->ticks();
size_t endStaff = staves().size();
for (size_t staffIdx = 0; staffIdx < endStaff; ++staffIdx) {
Rest* fmrest0 = 0; // full measure rest in voice 0
Rest* fmrest0 = nullptr; // full measure rest in voice 0
Fraction voices[VOICES];
#ifndef NDEBUG
@ -124,16 +158,13 @@ Ret Score::sanityCheck()
#endif
for (Segment* s = m->first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
for (size_t v = 0; v < VOICES; ++v) {
EngravingItem* element = s->element(static_cast<int>(staffIdx) * VOICES + static_cast<int>(v));
for (voice_idx_t v = 0; v < VOICES; ++v) {
EngravingItem* element = s->element(staffIdx * VOICES + v);
if (!element) {
continue;
}
ChordRest* cr = toChordRest(element);
if (cr == 0) {
continue;
}
voices[v] += cr->actualTicks();
if (v == 0 && cr->isRest()) {
Rest* r = toRest(cr);
@ -152,16 +183,17 @@ Ret Score::sanityCheck()
}
if (!repeatsIsValid) {
errors << mtrc("engraving", u"<b>Corrupted measure</b>: Measure %1, Staff %2.")
.arg(mNumber).arg(staffIdx + 1);
errors << mtrc("engraving", u"<b>Corrupted measure</b>: %1, measure %2, staff %3.")
.arg(excerptInfo()).arg(mNumber).arg(staffIdx + 1);
#ifndef NDEBUG
m->setCorrupted(staffIdx, true);
#endif
}
if (voices[0] != mLen) {
errors << mtrc("engraving", u"<b>Incomplete measure</b>: Measure %1, Staff %2. Found: %3. Expected: %4.")
.arg(mNumber).arg(staffIdx + 1).arg(voices[0].toString(), mLen.toString());
//: %1 describes in which score the corruption is (either `Full score` or `"[part name]" part score`)
errors << mtrc("engraving", u"<b>Incomplete measure</b>: %1, measure %2, staff %3. Found: %4. Expected: %5.")
.arg(excerptInfo()).arg(mNumber).arg(staffIdx + 1).arg(voices[0].toString(), mLen.toString());
#ifndef NDEBUG
m->setCorrupted(staffIdx, true);
#endif
@ -171,10 +203,12 @@ Ret Score::sanityCheck()
fmrest0->setTicks(mLen);
}
}
for (voice_idx_t v = 1; v < VOICES; ++v) {
if (voices[v] > mLen) {
errors << mtrc("engraving", u"<b>Voice too long</b>: Measure %1, Staff %2, Voice %3. Found: %4. Expected: %5.")
.arg(mNumber).arg(staffIdx + 1).arg(v + 1).arg(voices[v].toString(), mLen.toString());
//: %1 describes in which score the corruption is (either `Full score` or `"[part name]" part score`)
errors << mtrc("engraving", u"<b>Voice too long</b>: %1, measure %2, staff %3, voice %4. Found: %5. Expected: %6.")
.arg(excerptInfo()).arg(mNumber).arg(staffIdx + 1).arg(v + 1).arg(voices[v].toString(), mLen.toString());
#ifndef NDEBUG
m->setCorrupted(staffIdx, true);
#endif

View file

@ -233,6 +233,8 @@ public:
String name() const override;
Ret sanityCheck();
void setWidthOfSegmentCell(double val) { m_widthOfSegmentCell = val; }
double widthOfSegmentCell() const { return m_widthOfSegmentCell; }
};

View file

@ -1211,7 +1211,7 @@ public:
String createRehearsalMarkText(RehearsalMark* current) const;
String nextRehearsalMarkText(RehearsalMark* previous, RehearsalMark* current) const;
Ret sanityCheck();
Ret sanityCheckLocal();
bool checkKeys();

View file

@ -60,19 +60,22 @@ Column {
anchors.fill: parent
anchors.margins: 1
contentWidth: contentItem.childrenRect.width
flickableDirection: Flickable.AutoFlickDirection
spacing: 0
model: detailsModel
NavigationPanel {
id: detailsViewNavPanel
id: detailsViewNavPanel
name: "DetailsViewNavPanel"
order: root.navigationOrder
enabled: root.enabled && root.visible
direction: NavigationPanel.Horizontal
section: root.navigationSection
}
name: "DetailsViewNavPanel"
order: root.navigationOrder
enabled: root.enabled && root.visible
direction: NavigationPanel.Horizontal
section: root.navigationSection
}
delegate: ListItemBlank {
navigation.name: "Error " + model.index
@ -88,9 +91,14 @@ Column {
background.color: model.index % 2 === 0 ? ui.theme.backgroundSecondaryColor : "transparent"
mouseArea.enabled: false
implicitWidth: label.implicitWidth + 2 * 30
width: Math.max(ListView.view.width, implicitWidth)
StyledTextLabel {
id: label
anchors.fill: parent
anchors.leftMargin: 30
anchors.rightMargin: 30
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
@ -108,14 +116,14 @@ Column {
spacing: 0
NavigationPanel {
id: copyDetailsNavPanel
id: copyDetailsNavPanel
name: "CopyDetailsNavPanel"
order: root.navigationOrder + 1
enabled: root.enabled && root.visible
direction: NavigationPanel.Horizontal
section: root.navigationSection
}
name: "CopyDetailsNavPanel"
order: root.navigationOrder + 1
enabled: root.enabled && root.visible
direction: NavigationPanel.Horizontal
section: root.navigationSection
}
FlatButton {
text: qsTrc("global", "Copy")
@ -167,7 +175,7 @@ Column {
AccessibleItem {
id: accessibleInfo
accessibleParent: copyDetailsNavPanel.navigationPanel.accessible
accessibleParent: copyDetailsNavPanel.accessible
visualItem: detailsCopiedMessage
role: MUAccessible.StaticText
name: detailsCopiedMessage.text