Merge pull request #15988 from cbjeukendrup/corruption_check_parts
Also check part scores for corruptions
This commit is contained in:
commit
695701af3e
|
@ -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
|
||||
|
|
|
@ -233,6 +233,8 @@ public:
|
|||
|
||||
String name() const override;
|
||||
|
||||
Ret sanityCheck();
|
||||
|
||||
void setWidthOfSegmentCell(double val) { m_widthOfSegmentCell = val; }
|
||||
double widthOfSegmentCell() const { return m_widthOfSegmentCell; }
|
||||
};
|
||||
|
|
|
@ -1211,7 +1211,7 @@ public:
|
|||
String createRehearsalMarkText(RehearsalMark* current) const;
|
||||
String nextRehearsalMarkText(RehearsalMark* previous, RehearsalMark* current) const;
|
||||
|
||||
Ret sanityCheck();
|
||||
Ret sanityCheckLocal();
|
||||
|
||||
bool checkKeys();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue