fix #292474 ambitus crash in plugins

Resolves: https://musescore.org/en/node/292474

This also resolves this issue reported in the forum: https://musescore.org/en/node/294734

It was achieved by extending plugin functionalities from commit c77d904eaa. By adding:
* Support for elements that were causing application to crash such as: symbol, fingering, bend, notehead (note level), and clef and ambitus.
* You can now add and remove elements from notes using `Note::add()` and `Note::remove()`.
This commit is contained in:
Eduardo Rodrigues 2019-10-17 17:50:15 +02:00
parent 417f33bc88
commit 99d3dd9ec9
No known key found for this signature in database
GPG key ID: 832D7975F1AC442A
3 changed files with 153 additions and 4 deletions

View file

@ -172,7 +172,7 @@ void Cursor::add(Element* wrapped)
// Ensure that the object has the expected ownership
if (wrapped->ownership() == Ownership::SCORE) {
qWarning("Chord::add: Cannot add this element. The element is already part of the score.");
qWarning("Cursor::add: Cannot add this element. The element is already part of the score.");
return; // Don't allow operation.
}
@ -197,6 +197,7 @@ void Cursor::add(Element* wrapped)
}
else {
switch (s->type()) {
// To be added at measure level
case ElementType::MEASURE_NUMBER:
case ElementType::SPACER:
case ElementType::JUMP:
@ -210,6 +211,7 @@ void Cursor::add(Element* wrapped)
break;
}
// To be added at chord level
case ElementType::NOTE:
case ElementType::ARPEGGIO:
case ElementType::TREMOLO:
@ -221,8 +223,10 @@ void Cursor::add(Element* wrapped)
Chord::addInternal(toChord(curElement), s);
}
break;
break;
}
// To be added at chord/rest level
case ElementType::LYRICS: {
Ms::Element* curElement = currentElement();
if (curElement->isChordRest()) {
@ -232,7 +236,53 @@ void Cursor::add(Element* wrapped)
break;
}
default:
// To be added to a note
case ElementType::SYMBOL:
case ElementType::FINGERING:
case ElementType::BEND:
case ElementType::NOTEHEAD: {
Ms::Element* curElement = currentElement();
if (curElement->isChord()) {
Ms::Chord* chord = toChord(curElement);
Ms::Note* note = nullptr;
if (chord->notes().size() > 0) {
// Get first note from chord to add element
note = chord->notes().front();
}
if (note) {
Note::addInternal(note, s);
}
}
break;
}
// To be added to a segment (clef subtype)
case ElementType::CLEF:
case ElementType::AMBITUS: {
Ms::Element* parent = nullptr;
// Find backwards first measure containing a clef
for (Ms::Measure* m = _segment->measure(); m != 0; m = m->prevMeasure()) {
Ms::Segment* seg = m->findSegment(SegmentType::Clef | SegmentType::HeaderClef, m->tick());
if (seg != 0) {
parent = m->undoGetSegmentR(s->isAmbitus() ? SegmentType::Ambitus : seg->segmentType(), Fraction(0,1));
break;
}
}
if (parent && parent->isSegment()) {
if (s->isClef()) {
Ms::Clef* clef = toClef(s);
if (clef->clefType() == Ms::ClefType::INVALID) {
clef->setClefType(Ms::ClefType::G);
}
}
s->setParent(parent);
s->setTrack(_track);
_score->undoAddElement(s);
}
break;
}
default: // All others will be added to the current segment
_score->undoAddElement(s);
break;
}

View file

@ -70,6 +70,93 @@ void Note::setTpc(int val)
set(Pid::TPC2, val);
}
//---------------------------------------------------------
// Note::isChildAllowed
/// Check if element type can be a child of note.
/// \since MuseScore 3.3.3
//---------------------------------------------------------
bool Note::isChildAllowed(Ms::ElementType elementType)
{
switch(elementType) {
case ElementType::NOTEHEAD:
case ElementType::NOTEDOT:
case ElementType::FINGERING:
case ElementType::SYMBOL:
case ElementType::IMAGE:
case ElementType::TEXT:
case ElementType::BEND:
case ElementType::TIE:
case ElementType::ACCIDENTAL:
case ElementType::TEXTLINE:
case ElementType::GLISSANDO:
return true;
default:
return false;
}
}
//---------------------------------------------------------
// Note::add
/// \since MuseScore 3.3.3
//---------------------------------------------------------
void Note::add(Ms::PluginAPI::Element* wrapped)
{
Ms::Element* s = wrapped ? wrapped->element() : nullptr;
if (s)
{
// Ensure that the object has the expected ownership
if (wrapped->ownership() == Ownership::SCORE) {
qWarning("Note::add: Cannot add this element. The element is already part of the score.");
return; // Don't allow operation.
}
// Score now owns the object.
wrapped->setOwnership(Ownership::SCORE);
addInternal(note(), s);
}
}
//---------------------------------------------------------
// Note::addInternal
/// \since MuseScore 3.3.3
//---------------------------------------------------------
void Note::addInternal(Ms::Note* note, Ms::Element* s)
{
// Provide parentage for element.
s->setParent(note);
s->setTrack(note->track());
if (s && isChildAllowed(s->type())) {
// Create undo op and add the element.
toScore(note->score())->undoAddElement(s);
}
else if (s) {
qDebug("Note::add() not impl. %s", s->name());
}
}
//---------------------------------------------------------
// Note::remove
/// \since MuseScore 3.3.3
//---------------------------------------------------------
void Note::remove(Ms::PluginAPI::Element* wrapped)
{
Ms::Element* s = wrapped->element();
if (!s)
qWarning("PluginAPI::Note::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
else if (s->parent() != note())
qWarning("PluginAPI::Note::remove: The element is not a child of this note. Use removeElement() instead.");
else if (isChildAllowed(s->type()))
note()->score()->deleteItem(s); // Create undo op and remove the element.
else
qDebug("Note::remove() not impl. %s", s->name());
}
//---------------------------------------------------------
// Chord::setPlayEventType
//---------------------------------------------------------
@ -129,11 +216,13 @@ void Chord::addInternal(Ms::Chord* chord, Ms::Element* s)
void Chord::remove(Ms::PluginAPI::Element* wrapped)
{
Ms::Element* s = wrapped->element();
if (s->parent() != chord())
if (!s)
qWarning("PluginAPI::Chord::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
else if (s->parent() != chord())
qWarning("PluginAPI::Chord::remove: The element is not a child of this chord. Use removeElement() instead.");
else if (chord()->notes().size() <= 1 && s->type() == ElementType::NOTE)
qWarning("PluginAPI::Chord::remove: Removal of final note is not allowed.");
else if (s)
else
chord()->score()->deleteItem(s); // Create undo op and remove the element.
}

View file

@ -476,11 +476,21 @@ class Note : public Element {
Ms::AccidentalType accidentalType() { return note()->accidentalType(); }
void setAccidentalType(Ms::AccidentalType t) { note()->setAccidentalType(t); }
Ms::NoteType noteType() { return note()->noteType(); }
static void addInternal(Ms::Note* note, Ms::Element* el);
static bool isChildAllowed(Ms::ElementType elementType);
/// \endcond
/// Creates a PlayEvent object for use in Javascript.
/// \since MuseScore 3.3
Q_INVOKABLE Ms::PluginAPI::PlayEvent* createPlayEvent() { return playEventWrap(new NoteEvent(), nullptr); }
/// Add to a note's elements.
/// \since MuseScore 3.3.3
Q_INVOKABLE void add(Ms::PluginAPI::Element* wrapped);
/// Remove a note's element.
/// \since MuseScore 3.3.3
Q_INVOKABLE void remove(Ms::PluginAPI::Element* wrapped);
};
//---------------------------------------------------------