From aeb4919e775f26be52b438ac3a636c64527a49e2 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Thu, 29 Nov 2018 15:48:20 +0200 Subject: [PATCH 1/3] Avoid copying Selection objects This also fixes probably an error with not updating a selection in ScoreView::cmdChangeEnharmonic since the own copy was modified. --- libmscore/cmd.cpp | 6 ++---- libmscore/edit.cpp | 2 +- mscore/palette.cpp | 5 ++--- mscore/pianotools.cpp | 4 ++-- mscore/pianotools.h | 4 ++-- mscore/pianoview.cpp | 4 ++-- mscore/scoreview.cpp | 2 +- mscore/timeline.cpp | 4 ++-- 8 files changed, 14 insertions(+), 17 deletions(-) diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index 4928a330bb..eefab8314f 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -2479,16 +2479,14 @@ void Score::cmdExplode() lastStaff = qMin(nstaves(), srcStaff + n); } - // make our own copy of selection, since pasting modifies actual selection - Selection srcSelection(selection()); - + const QByteArray mimeData(selection().mimeData()); // copy to all destination staves Segment* firstCRSegment = startMeasure->tick2segment(startMeasure->tick()); for (int i = 1; srcStaff + i < lastStaff; ++i) { int track = (srcStaff + i) * VOICES; ChordRest* cr = toChordRest(firstCRSegment->element(track)); if (cr) { - XmlReader e(srcSelection.mimeData()); + XmlReader e(mimeData); e.setPasteMode(true); pasteStaff(e, cr->segment(), cr->staffIdx()); } diff --git a/libmscore/edit.cpp b/libmscore/edit.cpp index 8d8537fe5e..7a69bf8888 100644 --- a/libmscore/edit.cpp +++ b/libmscore/edit.cpp @@ -1254,7 +1254,7 @@ void Score::cmdAddTie() void Score::cmdAddOttava(OttavaType type) { - Selection sel = selection(); + const Selection& sel = selection(); // add on each staff if possible if (sel.isRange() && sel.staffStart() != sel.staffEnd() - 1) { for (int staffIdx = sel.staffStart() ; staffIdx < sel.staffEnd(); ++staffIdx) { diff --git a/mscore/palette.cpp b/mscore/palette.cpp index 144a66284a..513cea13df 100644 --- a/mscore/palette.cpp +++ b/mscore/palette.cpp @@ -451,7 +451,7 @@ void Palette::applyPaletteElement(PaletteCell* cell, Qt::KeyboardModifiers modif Score* score = mscore->currentScore(); if (score == 0) return; - Selection sel = score->selection(); // make a copy of the list + const Selection& sel = score->selection(); // make a copy of the list if (sel.isNone()) return; @@ -753,8 +753,7 @@ void Palette::mouseDoubleClickEvent(QMouseEvent* ev) Score* score = mscore->currentScore(); if (score == 0) return; - Selection sel = score->selection(); // make a copy of the list - if (sel.isNone()) + if (score->selection().isNone()) return; applyPaletteElement(cellAt(i), ev->modifiers()); diff --git a/mscore/pianotools.cpp b/mscore/pianotools.cpp index 914db38532..d23508cfe7 100644 --- a/mscore/pianotools.cpp +++ b/mscore/pianotools.cpp @@ -184,7 +184,7 @@ void HPiano::releasePitch(int pitch) // changeSelection //--------------------------------------------------------- -void HPiano::changeSelection(Selection selection) +void HPiano::changeSelection(const Selection& selection) { for (PianoKeyItem* key : keys) { key->setHighlighted(false); @@ -533,7 +533,7 @@ bool HPiano::gestureEvent(QGestureEvent *event) // changeSelection //--------------------------------------------------------- -void PianoTools::changeSelection(Selection selection) +void PianoTools::changeSelection(const Selection& selection) { _piano->changeSelection(selection); } diff --git a/mscore/pianotools.h b/mscore/pianotools.h index 06f780ca30..86b757df19 100644 --- a/mscore/pianotools.h +++ b/mscore/pianotools.h @@ -79,7 +79,7 @@ class HPiano : public QGraphicsView { void pressPitch(int pitch); void releasePitch(int pitch); void clearSelection(); - void changeSelection(Selection selection); + void changeSelection(const Selection& selection); void updateAllKeys(); virtual QSize sizeHint() const; @@ -110,7 +110,7 @@ class PianoTools : public QDockWidget { void releasePitch(int pitch) { _piano->releasePitch(pitch); } void heartBeat(QList notes); void clearSelection(); - void changeSelection(Selection selection); + void changeSelection(const Selection& selection); }; diff --git a/mscore/pianoview.cpp b/mscore/pianoview.cpp index 85bc47a01f..8a62a44c24 100644 --- a/mscore/pianoview.cpp +++ b/mscore/pianoview.cpp @@ -937,7 +937,8 @@ void PianoView::selectNotes(int startTick, int endTick, int lowPitch, int highPi //score->masterScore()->cmdState().reset(); // DEBUG: should not be necessary score->startCmd(); - Selection selection(score); + Selection& selection = score->selection(); + selection.deselectAll(); for (int i = 0; i < noteList.size(); ++i) { PianoItem* pi = noteList[i]; @@ -967,7 +968,6 @@ void PianoView::selectNotes(int startTick, int endTick, int lowPitch, int highPi selection.add(pi->note()); } - score->setSelection(selection); for (MuseScoreView* view : score->getViewer()) view->updateAll(); diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 607c1dc4c6..292e33e65d 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -3308,7 +3308,7 @@ void ScoreView::cmdAddNoteLine() void ScoreView::cmdChangeEnharmonic(bool both) { _score->startCmd(); - Selection selection = _score->selection(); + Selection& selection = _score->selection(); QList notes = selection.uniqueNotes(); for (Note* n : notes) { Staff* staff = n->staff(); diff --git a/mscore/timeline.cpp b/mscore/timeline.cpp index d81956f087..873e90261a 100644 --- a/mscore/timeline.cpp +++ b/mscore/timeline.cpp @@ -1726,8 +1726,8 @@ void Timeline::drawSelection() std::set> meta_labels_set; - const Selection selection = _score->selection(); - QList el = selection.elements(); + const Selection& selection = _score->selection(); + const QList& el = selection.elements(); for (Element* element : el) { if (element->tick() == -1) continue; From 5fc18d13cb632dcb85983714262777cbaf5ac87c Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Thu, 29 Nov 2018 17:03:07 +0200 Subject: [PATCH 2/3] Write score data to .mscz before pictures and thumbnails This preserves the score data in case of any further failures, e.g. on thumbnails writing (see issue #87241). --- libmscore/score.h | 2 +- libmscore/scorefile.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libmscore/score.h b/libmscore/score.h index 19d3c535a0..630f122376 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -758,7 +758,7 @@ class Score : public QObject, public ScoreElement { bool saveFile(QFileInfo& info); bool saveFile(QIODevice* f, bool msczFormat, bool onlySelection = false); bool saveCompressedFile(QFileInfo&, bool onlySelection); - bool saveCompressedFile(QIODevice*, QFileInfo&, bool onlySelection, bool createThumbnail = true); + bool saveCompressedFile(QFileDevice*, QFileInfo&, bool onlySelection, bool createThumbnail = true); bool exportFile(); void print(QPainter* printer, int page); diff --git a/libmscore/scorefile.cpp b/libmscore/scorefile.cpp index 4002358453..8a1713dabc 100644 --- a/libmscore/scorefile.cpp +++ b/libmscore/scorefile.cpp @@ -546,7 +546,7 @@ QImage Score::createThumbnail() // file is already opened //--------------------------------------------------------- -bool Score::saveCompressedFile(QIODevice* f, QFileInfo& info, bool onlySelection, bool doCreateThumbnail) +bool Score::saveCompressedFile(QFileDevice* f, QFileInfo& info, bool onlySelection, bool doCreateThumbnail) { MQZipWriter uz(f); @@ -572,6 +572,14 @@ bool Score::saveCompressedFile(QIODevice* f, QFileInfo& info, bool onlySelection //uz.addDirectory("META-INF"); uz.addFile("META-INF/container.xml", cbuf.data()); + QBuffer dbuf; + dbuf.open(QIODevice::ReadWrite); + saveFile(&dbuf, true, onlySelection); + dbuf.seek(0); + uz.addFile(fn, dbuf.data()); + f->flush(); // flush to preserve score data in case of + // any failures on the further operations. + // save images //uz.addDirectory("Pictures"); foreach (ImageStoreItem* ip, imageStore) { @@ -620,11 +628,6 @@ bool Score::saveCompressedFile(QIODevice* f, QFileInfo& info, bool onlySelection if (_audio) uz.addFile("audio.ogg", _audio->data()); - QBuffer dbuf; - dbuf.open(QIODevice::ReadWrite); - saveFile(&dbuf, true, onlySelection); - dbuf.seek(0); - uz.addFile(fn, dbuf.data()); uz.close(); return true; } From 247802bb9406d734c7e8efb8fb2726fb995e39e5 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Fri, 30 Nov 2018 10:04:24 +0200 Subject: [PATCH 3/3] fix #87241, fix #279064: Remove elements from selection on destruction --- libmscore/element.cpp | 9 +-------- libmscore/layout.cpp | 3 +-- libmscore/score.cpp | 20 ++++++++++++++++++++ libmscore/score.h | 3 +++ libmscore/select.cpp | 5 +++-- libmscore/select.h | 1 - 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/libmscore/element.cpp b/libmscore/element.cpp index 21e6e7fe5f..5b5c5a3dce 100644 --- a/libmscore/element.cpp +++ b/libmscore/element.cpp @@ -186,14 +186,7 @@ Element::Element(const Element& e) Element::~Element() { -#if 0 - if (score() && flag(ElementFlag::SELECTED)) { - if (score()->selection().elements().removeOne(this)) - printf("remove element from selection\n"); - else - printf("element not in selection\n"); - } -#endif + Score::onElementDestruction(this); } //--------------------------------------------------------- diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 3a44a38af3..7c3537dd00 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -3825,8 +3825,7 @@ void Score::doLayoutRange(int stick, int etick) for (System* s : _systems) { for (Bracket* b : s->brackets()) { if (b->selected()) { - _selection.elements().removeOne(b); - _selection.updateState(); + _selection.remove(b); setSelectionChanged(true); } } diff --git a/libmscore/score.cpp b/libmscore/score.cpp index 3f78a49f51..be3c9f0280 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -74,6 +74,7 @@ namespace Ms { MasterScore* gscore; ///< system score, used for palettes etc. +std::set Score::validScores; bool scriptDebug = false; bool noSeq = false; @@ -244,6 +245,7 @@ void MeasureBaseList::change(MeasureBase* ob, MeasureBase* nb) Score::Score() : ScoreElement(this), _is(this), _selection(this), _selectionFilter(this) { + Score::validScores.insert(this); _masterScore = 0; Layer l; l.name = "default"; @@ -265,6 +267,7 @@ Score::Score() Score::Score(MasterScore* parent) : Score{} { + Score::validScores.insert(this); _masterScore = parent; if (MScore::defaultStyleForParts()) _style = *MScore::defaultStyleForParts(); @@ -301,6 +304,7 @@ Score::Score(MasterScore* parent) Score::Score(MasterScore* parent, const MStyle& s) : Score{parent} { + Score::validScores.erase(this); _style = s; } @@ -353,6 +357,22 @@ Score* Score::clone() return score; } +//--------------------------------------------------------- +// Score::onElementDestruction +// Ensure correct state of the score after destruction +// of the element (e.g. remove invalid pointers etc.). +//--------------------------------------------------------- + +void Score::onElementDestruction(Element* e) + { + Score* score = e->score(); + if (!score || Score::validScores.find(score) == Score::validScores.end()) { + // No score or the score is already deleted + return; + } + score->selection().remove(e); + } + //--------------------------------------------------------- // addMeasure //--------------------------------------------------------- diff --git a/libmscore/score.h b/libmscore/score.h index 630f122376..09ceec083a 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -387,6 +387,7 @@ class Score : public QObject, public ScoreElement { }; private: + static std::set validScores; int _linkId { 0 }; MasterScore* _masterScore { 0 }; QList viewer; @@ -560,6 +561,8 @@ class Score : public QObject, public ScoreElement { virtual bool isMaster() const { return false; } virtual bool readOnly() const; + static void onElementDestruction(Element* se); + virtual inline QList& excerpts(); virtual inline const QList& excerpts() const; diff --git a/libmscore/select.cpp b/libmscore/select.cpp index 5568c221bc..a9a3336d2a 100644 --- a/libmscore/select.cpp +++ b/libmscore/select.cpp @@ -319,9 +319,10 @@ void Selection::clear() void Selection::remove(Element* el) { - _el.removeOne(el); + const bool removed = _el.removeOne(el); el->setSelected(false); - updateState(); + if (removed) + updateState(); } //--------------------------------------------------------- diff --git a/libmscore/select.h b/libmscore/select.h index fc045d190c..f0b7c3f622 100644 --- a/libmscore/select.h +++ b/libmscore/select.h @@ -157,7 +157,6 @@ class Selection { void setState(SelState s); const QList& elements() const { return _el; } - QList& elements() { return _el; } std::vector noteList(int track = -1) const; const QList uniqueElements() const;