    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2012 Werner Schweer
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2
    //  as published by the Free Software Foundation and appearing in
    //  the file LICENCE.GPL
    //=============================================================================

    #include "score.h"

    #include "rest.h"
    #include "staff.h"
    #include "measure.h"
    #include "harmony.h"
    #include "fret.h"
    #include "breath.h"
    #include "beam.h"
    #include "figuredbass.h"
    #include "ottava.h"
    #include "part.h"
    #include "lyrics.h"
    #include "hairpin.h"
    #include "tie.h"
    #include "tuplet.h"
    #include "utils.h"
    #include "xml.h"
    #include "image.h"
    #include "repeat.h"
    #include "chord.h"
    #include "tremolo.h"
    #include "slur.h"
    #include "articulation.h"

    namespace Ms {

    //---------------------------------------------------------
    //   transposeChord
    //---------------------------------------------------------

    static void transposeChord(Chord* c, Interval srcTranspose, int tick)
          {
          // set note track
          // check if staffMove moves a note to a
          // nonexistant staff
          //
          int track  = c->track();
          int nn     = (track / VOICES) + c->staffMove();
          if (nn < 0 || nn >= c->score()->nstaves())
                c->setStaffMove(0);
          Part* part = c->part();
          Interval dstTranspose = part->instrument(tick)->transpose();

          if (srcTranspose != dstTranspose) {
                if (!dstTranspose.isZero()) {
                      dstTranspose.flip();
                      for (Note* n : c->notes()) {
                            int npitch;
                            int ntpc;
                            transposeInterval(n->pitch(), n->tpc1(), &npitch, &ntpc, dstTranspose, true);
                            n->setTpc2(ntpc);
                            }
                      }
                else {
                      for (Note* n : c->notes())
                            n->setTpc2(n->tpc1());
                      }
                }
          }

    //---------------------------------------------------------
    //   pasteStaff
    //    return false if paste fails
    //---------------------------------------------------------

    bool Score::pasteStaff(XmlReader& e, Segment* dst, int dstStaff)
          {
          Q_ASSERT(dst->segmentType() == SegmentType::ChordRest);
          QList<Chord*> graceNotes;
          int dstTick = dst->tick();
          bool pasted = false;
          int tickLen = 0;
          int staves  = 0;
          bool done   = false;
          while (e.readNextStartElement()) {
                if (done)
                      break;
                if (e.name() != "StaffList") {
                      e.unknown();
                      break;
                      }
                QString version = e.attribute("version", "NONE");
                if (!MScore::testMode) {
                      if (version != MSC_VERSION) {
                            qDebug("pasteStaff: bad version");
                            break;
                            }
                      }
                int tickStart     = e.intAttribute("tick", 0);
                    tickLen       = e.intAttribute("len", 0);
                int staffStart    = e.intAttribute("staff", 0);
                    staves        = e.intAttribute("staves", 0);
                int voiceOffset[VOICES];
                std::fill(voiceOffset,voiceOffset+VOICES,-1);

                e.setTickOffset(dstTick - tickStart);
                e.initTick(0);

                while (e.readNextStartElement()) {
                      if (done)
                            break;
                      if (e.name() != "Staff") {
                            e.unknown();
                            break;
                            }
                      e.setTransposeChromatic(0);
                      e.setTransposeDiatonic(0);

                      int srcStaffIdx = e.attribute("id", "0").toInt();
                      e.setTrack(srcStaffIdx * VOICES);
                      e.setTrackOffset((dstStaff - staffStart) * VOICES);
                      int dstStaffIdx = e.track() / VOICES;
                      if (dstStaffIdx >= dst->score()->nstaves()) {
                            qDebug("paste beyond staves");
                            done = true;
                            break;
                            }

                      e.tuplets().clear();
                      bool makeGap  = true;
                      while (e.readNextStartElement()) {
                            pasted = true;
                            const QStringRef& tag(e.name());

                            if (tag == "transposeChromatic")
                                  e.setTransposeChromatic(e.readInt());
                            else if (tag == "transposeDiatonic")
                                  e.setTransposeDiatonic(e.readInt());
                            else if (tag == "voice") {
                                  int voiceId = e.attribute("id", "-1").toInt();
                                  Q_ASSERT(voiceId >= 0 && voiceId < VOICES);
                                  voiceOffset[voiceId] = e.readInt();
                                  }
                            else if (tag == "move" || tag == "tick") {
                                  int tick = tag == "move" ? e.readFraction().ticks() : e.readInt();
                                  e.initTick(tick);
                                  int shift = tick - tickStart;
                                  if (makeGap && !makeGap1(dstTick, dstStaffIdx, Fraction::fromTicks(tickLen), voiceOffset)) {
                                        qDebug("cannot make gap in staff %d at tick %d", dstStaffIdx, dstTick + shift);
                                        done = true; // break main loop, cannot make gap
                                        break;
                                        }
                                  makeGap = false; // create gap only once per staff
                                  }
                            else if (tag == "Tuplet") {
                                  Tuplet* tuplet = new Tuplet(this);
                                  tuplet->setTrack(e.track());
                                  tuplet->read(e);
                                  int tick = e.tick();
                                  // no paste into local time signature
                                  if (staff(dstStaffIdx)->isLocalTimeSignature(tick)) {
                                        MScore::setError(DEST_LOCAL_TIME_SIGNATURE);
                                        return false;
                                        }
                                  Measure* measure = tick2measure(tick);
                                  tuplet->setParent(measure);
                                  tuplet->setTick(tick);
                                  int ticks = tuplet->actualTicks();
                                  int rticks = measure->endTick() - tick;
                                  if (rticks < ticks) {
                                        delete tuplet;
                                        MScore::setError(TUPLET_CROSSES_BAR);
                                        return false;
                                        }
                                  e.addTuplet(tuplet);
                                  }
                            else if (tag == "Chord" || tag == "Rest" || tag == "RepeatMeasure") {
                                  ChordRest* cr = toChordRest(Element::name2Element(tag, this));
                                  cr->setTrack(e.track());
                                  cr->read(e);
                                  cr->setSelected(false);
                                  int tick = e.tick();
                                  // no paste into local time signature
                                  if (staff(dstStaffIdx)->isLocalTimeSignature(tick)) {
                                        MScore::setError(DEST_LOCAL_TIME_SIGNATURE);
                                        return false;
                                        }
                                  if (cr->isGrace())
                                        graceNotes.push_back(toChord(cr));
                                  else {
                                        e.incTick(cr->actualTicks());
                                        if (cr->isChord()) {
                                              Chord* chord = toChord(cr);
                                              // disallow tie across barline within two-note tremolo
                                              // tremolos can potentially still straddle the barline if no tie is required
                                              // but these will be removed later
                                              if (chord->tremolo() && chord->tremolo()->twoNotes()) {
                                                    Measure* m = tick2measure(tick);
                                                    int ticks = cr->actualTicks();
                                                    int rticks = m->endTick() - tick;
                                                    if (rticks < ticks || (rticks != ticks && rticks < ticks * 2)) {
                                                          MScore::setError(DEST_TREMOLO);
                                                          return false;
                                                          }
                                                    }
                                              for (int i = 0; i < graceNotes.size(); ++i) {
                                                    Chord* gc = graceNotes[i];
                                                    gc->setGraceIndex(i);
                                                    transposeChord(gc, e.transpose(), tick);
                                                    chord->add(gc);
                                                    }
                                              graceNotes.clear();
                                              }
                                        // delete pending ties, they are not selected when copy
                                        if ((tick - dstTick) + cr->actualTicks() >= tickLen) {
                                              if (cr->isChord()) {
                                                    Chord* c = toChord(cr);
                                                    for (Note* note: c->notes()) {
                                                          Tie* tie = note->tieFor();
                                                          if (tie) {
                                                                note->setTieFor(0);
                                                                delete tie;
                                                                }
                                                          }
                                                    }
                                              }
                                        // shorten last cr to fit in the space made by makeGap
                                        if ((tick - dstTick) + cr->actualTicks() > tickLen) {
                                              int newLength = tickLen - (tick - dstTick);
                                              // check previous CR on same track, if it has tremolo, delete the tremolo
                                              // we don't want a tremolo and two different chord durations
                                              if (cr->isChord()) {
                                                    Segment* s = tick2leftSegment(tick - 1);
                                                    if (s) {
                                                          ChordRest* crt = toChordRest(s->element(cr->track()));
                                                          if (!crt)
                                                                crt = s->nextChordRest(cr->track(), true);
                                                          if (crt && crt->isChord()) {
                                                                Chord* chrt = toChord(crt);
                                                                Tremolo* tr = chrt->tremolo();
                                                                if (tr) {
                                                                      tr->setChords(chrt, toChord(cr));
                                                                      chrt->remove(tr);
                                                                      delete tr;
                                                                      }
                                                                }
                                                          }
                                                    }
                                              if (!cr->tuplet()/*|| cr->actualTicks() - newLength > (cr->tuplet()->ratio().numerator() + 1 ) / 2*/) {
                                                    // shorten duration
                                                    // exempt notes in tuplets, since we don't allow copy of partial tuplet anyhow
                                                    // TODO: figure out a reasonable fudge factor to make sure shorten tuplets appropriately if we do ever copy a partial tuplet
                                                    cr->setDuration(Fraction::fromTicks(newLength));
                                                    cr->setDurationType(newLength);
                                                    }
                                              }
                                        pasteChordRest(cr, tick, e.transpose());
                                        }
                                  }
                            else if (tag == "HairPin"
                               || tag == "Pedal"
                               || tag == "Ottava"
                               || tag == "Trill"
                               || tag == "TextLine"
                               || tag == "Volta") {
                                  Spanner* sp = static_cast<Spanner*>(Element::name2Element(tag, this));
                                  sp->setAnchor(Spanner::Anchor::SEGMENT);
                                  sp->read(e);
                                  sp->setTrack(e.track());
                                  sp->setTrack2(e.track());
                                  sp->setTick(e.tick());
                                  addSpanner(sp);
                                  }
                            else if (tag == "Slur") {
                                  Slur* sp = new Slur(this);
                                  sp->read(e);
                                  sp->setTrack(e.track());
                                  sp->setTick(e.tick());
                                  // check if we saw endSpanner / stop element already
                                  int id = e.spannerId(sp);
                                  const SpannerValues* sv = e.spannerValues(id);
                                  if (sv) {
                                        sp->setTick2(sv->tick2);
                                        sp->setTrack2(sv->track2);
                                        }
                                  undoAddElement(sp);
                                  }
                            else if (tag == "endSpanner") {
                                  int id = e.intAttribute("id");
                                  Spanner* spanner = e.findSpanner(id);
                                  if (spanner) {
                                        // e.spanner().removeOne(spanner);
                                        spanner->setTick2(e.tick());
                                        removeSpanner(spanner);
                                        undoAddElement(spanner);
                                        if (spanner->isOttava())
                                              spanner->staff()->updateOttava();
                                        }
                                  e.readNext();
                                  }
                            else if (tag == "Harmony") {
                                  Harmony* harmony = new Harmony(this);
                                  harmony->setTrack(e.track());
                                  harmony->read(e);
                                  harmony->setTrack(e.track());
                                  // transpose
                                  Part* partDest = staff(e.track() / VOICES)->part();
                                  Interval interval = partDest->instrument(e.tick())->transpose();
                                  if (!styleB(StyleIdx::concertPitch) && !interval.isZero()) {
                                        interval.flip();
                                        int rootTpc = transposeTpc(harmony->rootTpc(), interval, true);
                                        int baseTpc = transposeTpc(harmony->baseTpc(), interval, true);
                                        undoTransposeHarmony(harmony, rootTpc, baseTpc);
                                        }

                                  int tick = e.tick();
                                  Measure* m = tick2measure(tick);
                                  Segment* seg = m->undoGetSegment(SegmentType::ChordRest, tick);
                                  if (seg->findAnnotationOrElement(ElementType::HARMONY, e.track(), e.track())) {
                                        QList<Element*> elements;
                                        foreach (Element* el, seg->annotations()) {
                                              if (el->isHarmony() && el->track() == e.track()) {
                                                    elements.append(el);
                                                    }
                                              }
                                        foreach (Element* el, elements)
                                              undoRemoveElement(el);
                                        }
                                  harmony->setParent(seg);
                                  undoAddElement(harmony);
                                  }
                            else if (tag == "Dynamic"
                               || tag == "Symbol"
                               || tag == "FretDiagram"
                               || tag == "TremoloBar"
                               || tag == "Marker"
                               || tag == "Jump"
                               || tag == "Image"
                               || tag == "Text"
                               || tag == "StaffText"
                               || tag == "TempoText"
                               || tag == "FiguredBass"
                               ) {
                                  Element* el = Element::name2Element(tag, this);
                                  el->setTrack(e.track());      // a valid track might be necessary for el->read() to work
                                  el->read(e);

                                  Measure* m = tick2measure(e.tick());
                                  Segment* seg = m->undoGetSegment(SegmentType::ChordRest, e.tick());
                                  el->setParent(seg);

                                  // be sure to paste the element in the destination track;
                                  // setting track needs to be repeated, as it might have been overwritten by el->read()
                                  // preserve *voice* from source, though
                                  el->setTrack((e.track() / VOICES) * VOICES + el->voice());

                                  undoAddElement(el);
                                  }
                            else if (tag == "Clef") {
                                  Clef* clef = new Clef(this);
                                  clef->read(e);
                                  clef->setTrack(e.track());
                                  int tick = e.tick();
                                  Measure* m = tick2measure(tick);
                                  if (m->tick() && m->tick() == tick)
                                        m = m->prevMeasure();
                                  Segment* segment = m->undoGetSegment(SegmentType::Clef, tick);
                                  clef->setParent(segment);
                                  undoChangeElement(segment->element(e.track()), clef);
                                  }
                            else if (tag == "Breath") {
                                  Breath* breath = new Breath(this);
                                  breath->read(e);
                                  breath->setTrack(e.track());
                                  int tick = e.tick();
                                  Measure* m = tick2measure(tick);
                                  Segment* segment = m->undoGetSegment(SegmentType::Breath, tick);
                                  breath->setParent(segment);
                                  undoChangeElement(segment->element(e.track()), breath);
                                  }
                            else if (tag == "Beam") {
                                  Beam* beam = new Beam(this);
                                  beam->setTrack(e.track());
                                  beam->read(e);
                                  beam->setParent(0);
                                  e.addBeam(beam);
                                  }
                            else if (tag == "BarLine") {
                                  e.skipCurrentElement();    // ignore bar line
                                  }
                            else {
                                  qDebug("PasteStaff: element %s not handled", tag.toUtf8().data());
                                  e.skipCurrentElement();    // ignore
                                  }
                            }

                      for (Tuplet* tuplet : e.tuplets()) {
                            Q_ASSERT(!tuplet->elements().empty());
                            Measure* measure = tick2measure(tuplet->tick());
                            tuplet->setParent(measure);
                            tuplet->sortElements();
                            }
                      }
                }
          for (Score* s : scoreList())     // for all parts
                s->connectTies();

          if (pasted) {                       //select only if we pasted something
    //TODO?            if (styleB(StyleIdx::createMultiMeasureRests))
    //                  createMMRests();
                Segment* s1 = tick2segmentMM(dstTick);
                Segment* s2 = tick2segmentMM(dstTick + tickLen);
                int endStaff = dstStaff + staves;
                if (endStaff > nstaves())
                      endStaff = nstaves();
                //check and add truly invisible rests insted of gaps
                //TODO: look if this could be done different
                Measure* dstM = tick2measureMM(dstTick);
                Measure* endM = tick2measureMM(dstTick + tickLen);
                for (int i = dstStaff; i < endStaff; i++) {
                      for (Measure* m = dstM; m && m != endM->nextMeasureMM(); m = m->nextMeasureMM())
                            m->checkMeasure(i);
                      }
                _selection.setRange(s1, s2, dstStaff, endStaff);
                _selection.updateSelectedElements();

                //finding the first element that has a track
                //the canvas position will be set to this element
                Element* e = 0;
                Segment* s = s1;
                bool found = false;
                if (s2)
                      s2 = s2->next1MM();
                while (!found && s != s2) {
                      for (int i = dstStaff * VOICES; i < (endStaff + 1) * VOICES; i++) {
                            e = s->element(i);
                            if (e) {
                                  found = true;
                                  break;
                                  }
                            }
                      s = s->next1MM();
                      }

                for (MuseScoreView* v : viewer)
                      v->adjustCanvasPosition(e, false);
                if (!selection().isRange())
                      _selection.setState(SelState::RANGE);
                }
          return true;
          }

    //---------------------------------------------------------
    //   pasteChordRest
    //---------------------------------------------------------

    void Score::pasteChordRest(ChordRest* cr, int tick, const Interval& srcTranspose)
          {
    // qDebug("pasteChordRest %s at %d, len %d/%d", cr->name(), tick, cr->duration().numerator(), cr->duration().denominator() );
          if (cr->isChord())
                transposeChord(toChord(cr), srcTranspose, tick);

          Measure* measure = tick2measure(tick);
          if (!measure)
                return;

          // we can paste a measure rest as such only at start of measure
          // and only if the lengths of the rest and measure match
          // otherwise, we need to convert to duration rest(s)
          // and potentially split the rest up (eg, 5/4 => whole + quarter)
          bool convertMeasureRest = cr->isRest() && cr->durationType().type() == TDuration::DurationType::V_MEASURE
             && (tick != measure->tick() || cr->duration() != measure->len());

          int measureEnd = measure->endTick();
          bool isGrace = cr->isChord() && toChord(cr)->noteType() != NoteType::NORMAL;

          // if note is too long to fit in measure, split it up with a tie across the barline
          // exclude tuplets from consideration
          // we have already disallowed a tuplet from crossing the barline, so there is no problem here
          // but due to rounding, it might appear from actualTicks() that the last note is too long by a couple of ticks

          if (!isGrace && !cr->tuplet() && (tick + cr->actualTicks() > measureEnd || convertMeasureRest)) {
                if (cr->isChord()) {
                      // split Chord
                      Chord* c = toChord(cr);
                      int rest = c->actualTicks();
                      bool firstpart = true;
                      while (rest) {
                            measure = tick2measure(tick);
                            Chord* c2 = firstpart ? c : toChord(c->clone());
                            if (!firstpart)
                                  c2->removeMarkings(true);
                            int mlen = measure->tick() + measure->ticks() - tick;
                            int len = mlen > rest ? rest : mlen;
                            std::vector<TDuration> dl = toDurationList(Fraction::fromTicks(len), true);
                            TDuration d = dl[0];
                            c2->setDurationType(d);
                            c2->setDuration(d.fraction());
                            rest -= c2->actualTicks();
                            undoAddCR(c2, measure, tick);

                            std::vector<Note*> nl1 = c->notes();
                            std::vector<Note*> nl2 = c2->notes();

                            if (!firstpart)
                                 for (unsigned i = 0; i < nl1.size(); ++i) {
                                        Tie* tie = new Tie(this);
                                        tie->setStartNote(nl1[i]);
                                        tie->setEndNote(nl2[i]);
                                        tie->setTrack(c->track());
                                        Tie* tie2 = nl1[i]->tieFor();
                                        if (tie2) {
                                              nl2[i]->setTieFor(nl1[i]->tieFor());
                                              tie2->setStartNote(nl2[i]);
                                              }
                                        nl1[i]->setTieFor(tie);
                                        nl2[i]->setTieBack(tie);
                                        }
                            c = c2;
                            firstpart = false;
                            tick += c->actualTicks();
                            }
                      }
                else if (cr->isRest()) {
                      // split Rest
                      Rest* r       = toRest(cr);
                      Fraction rest = r->duration();

                      bool firstpart = true;
                      while (!rest.isZero()) {
                            Rest* r2      = firstpart ? r : toRest(r->clone());
                            measure       = tick2measure(tick);
                            Fraction mlen = Fraction::fromTicks(measure->tick() + measure->ticks() - tick);
                            Fraction len  = rest > mlen ? mlen : rest;
                            std::vector<TDuration> dl = toDurationList(len, false);
                            TDuration d = dl[0];
                            r2->setDuration(d.fraction());
                            r2->setDurationType(d);
                            undoAddCR(r2, measure, tick);
                            rest -= d.fraction();
                            tick += r2->actualTicks();
                            firstpart = false;
                            }
                      }
                else if (cr->isRepeatMeasure()) {
                      RepeatMeasure* rm = toRepeatMeasure(cr);
                      std::vector<TDuration> list = toDurationList(rm->actualDuration(), true);
                      for (auto dur : list) {
                            Rest* r = new Rest(this, dur);
                            r->setTrack(cr->track());
                            Fraction rest = r->duration();
                            while (!rest.isZero()) {
                                  Rest* r2      = toRest(r->clone());
                                  measure       = tick2measure(tick);
                                  Fraction mlen = Fraction::fromTicks(measure->tick() + measure->ticks() - tick);
                                  Fraction len  = rest > mlen ? mlen : rest;
                                  std::vector<TDuration> dl = toDurationList(len, false);
                                  TDuration d = dl[0];
                                  r2->setDuration(d.fraction());
                                  r2->setDurationType(d);
                                  undoAddCR(r2, measure, tick);
                                  rest -= d.fraction();
                                  tick += r2->actualTicks();
                                  }
                            delete r;
                            }
                      delete cr;
                      }
                }
          else {
                undoAddCR(cr, measure, tick);
                }
          }

    //---------------------------------------------------------
    //   pasteSymbols
    //
    //    pastes a list of symbols into cr and following ChordRest's
    //
    //    (Note: info about delta ticks is currently ignored)
    //---------------------------------------------------------

    void Score::pasteSymbols(XmlReader& e, ChordRest* dst)
          {
          Segment* currSegm = dst->segment();
          int   destTick    = 0;              // the tick and track to place the pasted element at
          int   destTrack   = 0;
          bool  done        = false;
          int   segDelta    = 0;
          Segment* startSegm= currSegm;
          int   startTick   = dst->tick();    // the initial tick and track where to start pasting
          int   startTrack  = dst->track();
          int   maxTrack    = ntracks();
          int   lastTick    = lastSegment()->tick();

          while (e.readNextStartElement()) {
                if (done)
                      break;
                if (e.name() != "SymbolList") {
                      e.unknown();
                      break;
                      }
                QString version = e.attribute("version", "NONE");
                if (version != MSC_VERSION)
                      break;

                while (e.readNextStartElement()) {
                      if (done)
                            break;
                      const QStringRef& tag(e.name());

                      if (tag == "trackOffset") {
                            destTrack = startTrack + e.readInt();
                            currSegm  = startSegm;
                            }
                      else if (tag == "tickOffset")
                            destTick = startTick + e.readInt();
                      else if (tag == "segDelta")
                            segDelta = e.readInt();
                      else {

                            if (tag == "Harmony" || tag == "FretDiagram") {
                                  //
                                  // Harmony elements (= chord symbols) are positioned respecting
                                  // the original tickOffset: advance to destTick (or near)
                                  // same for FretDiagram elements
                                  //
                                  Segment* harmSegm;
                                  for (harmSegm = startSegm; harmSegm && (harmSegm->tick() < destTick);
                                              harmSegm = harmSegm->nextCR())
                                        ;
                                  // if destTick overshot, no dest. segment: create one
                                  if (destTick >= lastTick) {
                                        harmSegm = nullptr;
                                        }
                                  else if (!harmSegm || harmSegm->tick() > destTick) {
                                        Measure* meas     = tick2measure(destTick);
                                        harmSegm          = meas ? meas->undoGetSegment(SegmentType::ChordRest, destTick) : nullptr;
                                  }
                                  if (destTrack >= maxTrack || harmSegm == nullptr) {
                                        qDebug("PasteSymbols: no track or segment for %s", tag.toUtf8().data());
                                        e.skipCurrentElement();       // ignore
                                        continue;
                                        }
                                  if (tag == "Harmony") {
                                        Harmony* el = new Harmony(this);
                                        el->setTrack(trackZeroVoice(destTrack));
                                        el->read(e);
                                        el->setTrack(trackZeroVoice(destTrack));
                                        // transpose
                                        Part* partDest = staff(track2staff(destTrack))->part();
                                        Interval interval = partDest->instrument(destTick)->transpose();
                                        if (!styleB(StyleIdx::concertPitch) && !interval.isZero()) {
                                              interval.flip();
                                              int rootTpc = transposeTpc(el->rootTpc(), interval, true);
                                              int baseTpc = transposeTpc(el->baseTpc(), interval, true);
                                              undoTransposeHarmony(el, rootTpc, baseTpc);
                                              }
                                        el->setParent(harmSegm);
                                        undoAddElement(el);
                                        }
                                  else {
                                        FretDiagram* el = new FretDiagram(this);
                                        el->setTrack(trackZeroVoice(destTrack));
                                        el->read(e);
                                        el->setTrack(trackZeroVoice(destTrack));
                                        el->setParent(harmSegm);
                                        undoAddElement(el);
                                        }
                                  }
                            else {
                                  //
                                  // All other elements are positioned respecting the distance in chords
                                  //
                                  for ( ; currSegm && segDelta > 0; segDelta--)
                                        currSegm = currSegm->nextCR(destTrack);
                                  // check the intended dest. track and segment exist
                                  if (destTrack >= maxTrack || currSegm == nullptr) {
                                        qDebug("PasteSymbols: no track or segment for %s", tag.toUtf8().data());
                                        e.skipCurrentElement();       // ignore
                                        continue;
                                        }
                                  // check there is a segment element in the required track
                                  if (currSegm->element(destTrack) == nullptr) {
                                        qDebug("PasteSymbols: no track element for %s", tag.toUtf8().data());
                                        e.skipCurrentElement();
                                        continue;
                                        }
                                  ChordRest* cr = toChordRest(currSegm->element(destTrack));

                                  if (tag == "Articulation") {
                                        Articulation* el = new Articulation(this);
                                        el->read(e);
                                        el->setTrack(destTrack);
                                        el->setParent(cr);
                                        if (!el->isFermata() && cr->isRest())
                                              delete el;
                                        else
                                              undoAddElement(el);
                                        }
                                  else if (tag == "FiguredBass") {
                                        // FiguredBass always belongs to first staff voice
                                        destTrack = trackZeroVoice(destTrack);
                                        int ticks;
                                        FiguredBass* el = new FiguredBass(this);
                                        el->setTrack(destTrack);
                                        el->read(e);
                                        el->setTrack(destTrack);
                                        // if f.b. is off-note, we have to locate a place before currSegm
                                        // where an on-note f.b. element could (potentially) be
                                        // (while having an off-note f.b. without an on-note one before it
                                        // is un-idiomatic, possible mismatch in rhythmic patterns between
                                        // copy source and paste destination does not allow to be too picky)
                                        if (!el->onNote()) {
                                              FiguredBass* onNoteFB = nullptr;
                                              Segment*     prevSegm = currSegm;
                                              bool         done = false;
                                              while (prevSegm) {
                                                    if (done)
                                                          break;
                                                    prevSegm = prevSegm->prev1(SegmentType::ChordRest);
                                                    // if there is a ChordRest in the dest. track
                                                    // this segment is a (potential) f.b. location
                                                    if (prevSegm->element(destTrack) != nullptr) {
                                                          done = true;
                                                          }
                                                    // in any case, look for a f.b. in annotations:
                                                    // if there is a f.b. element in the right track,
                                                    // this is an (actual) f.b. location
                                                    foreach (Element* a, prevSegm->annotations()) {
                                                          if (a->isFiguredBass() && a->track() == destTrack) {
                                                                onNoteFB = toFiguredBass(a);
                                                                done = true;
                                                                }
                                                          }
                                                    }
                                              if (!prevSegm) {
                                                    qDebug("PasteSymbols: can't place off-note FiguredBass");
                                                    delete el;
                                                    continue;
                                                    }
                                              // by default, split on-note duration in half: half on-note and half off-note
                                              int totTicks = currSegm->tick() - prevSegm->tick();
                                              int destTick = prevSegm->tick() + totTicks / 2;
                                              ticks        = totTicks / 2;
                                              if (onNoteFB)
                                                    onNoteFB->setTicks(totTicks / 2);
                                              // look for a segment at this tick; if none, create one
                                              Segment * nextSegm = prevSegm;
                                              while (nextSegm && nextSegm->tick() < destTick)
                                                    nextSegm = nextSegm->next1(SegmentType::ChordRest);
                                              if (!nextSegm || nextSegm->tick() > destTick) {      // no ChordRest segm at this tick
                                                    nextSegm = new Segment(prevSegm->measure(), SegmentType::ChordRest, destTick);
                                                    if (!nextSegm) {
                                                          qDebug("PasteSymbols: can't find or create destination segment for FiguredBass");
                                                          delete el;
                                                          continue;
                                                          }
                                                    undoAddElement(nextSegm);
                                                    }
                                              currSegm = nextSegm;
                                              }
                                        else
                                              // by default, assign to FiguredBass element the duration of the chord it refers to
                                              ticks = toChordRest(currSegm->element(destTrack))->duration().ticks();
                                        // in both cases, look for an existing f.b. element in segment and remove it, if found
                                        FiguredBass* oldFB = nullptr;
                                        foreach (Element* a, currSegm->annotations()) {
                                              if (a->isFiguredBass() && a->track() == destTrack) {
                                                    oldFB = toFiguredBass(a);
                                                    break;
                                                    }
                                              }
                                        if (oldFB)
                                              undoRemoveElement(oldFB);
                                        el->setParent(currSegm);
                                        el->setTicks(ticks);
                                        undoAddElement(el);
                                        }
                                  else if (tag == "Lyrics") {
                                        // with lyrics, skip rests
                                        while (!cr->isChord() && currSegm) {
                                              currSegm = currSegm->nextCR(destTrack);
                                              if (currSegm)
                                                    cr = toChordRest(currSegm->element(destTrack));
                                              else
                                                    break;
                                              }
                                        if (currSegm == nullptr) {
                                              qDebug("PasteSymbols: no segment for Lyrics");
                                              e.skipCurrentElement();
                                              continue;
                                              }
                                        if (!cr->isChord()) {
                                              qDebug("PasteSymbols: can't paste Lyrics to rest");
                                              e.skipCurrentElement();
                                              continue;
                                              }
                                        Lyrics* el = new Lyrics(this);
                                        el->setTrack(destTrack);
                                        el->read(e);
                                        el->setTrack(destTrack);
                                        el->setParent(cr);
                                        undoAddElement(el);
                                        }
                                  else {
                                        qDebug("PasteSymbols: element %s not handled", tag.toUtf8().data());
                                        e.skipCurrentElement();    // ignore
                                        }
                                  }           // if !Harmony
                            }                 // if element
                      }                       // outer while readNextstartElement()
                }                             // inner while readNextstartElement()
          }                                   // pasteSymbolList()

    //---------------------------------------------------------
    //   cmdPaste
    //---------------------------------------------------------

    void Score::cmdPaste(const QMimeData* ms, MuseScoreView* view)
          {
          if (ms == 0) {
                qDebug("no application mime data");
                MScore::setError(NO_MIME);
                return;
                }
          if ((_selection.isSingle() || _selection.isList()) && ms->hasFormat(mimeSymbolFormat)) {
                QByteArray data(ms->data(mimeSymbolFormat));
                XmlReader e(this, data);
                QPointF dragOffset;
                Fraction duration(1, 4);
                ElementType type = Element::readType(e, &dragOffset, &duration);

                QList<Element*> els;
                if (_selection.isSingle())
                      els.append(_selection.element());
                else
                      els.append(_selection.elements());

                if (type != ElementType::INVALID) {
                      Element* el = Element::create(type, this);
                      if (el) {
                            el->read(e);
                            if (el) {
                                  for (Element* target : els) {
                                        Element* nel = el->clone();
                                        addRefresh(target->abbox());   // layout() ?!
                                        EditData ddata(view);
                                        ddata.view       = view;
                                        ddata.element    = nel;
                                        ddata.duration   = duration;
                                        if (target->acceptDrop(ddata)) {
                                              target->drop(ddata);
                                              if (_selection.element())
                                                    addRefresh(_selection.element()->abbox());
                                              }
                                        }
                                  }
                                  delete el;
                            }
                      }
                else
                      qDebug("cannot read type");
                }
          else if ((_selection.isRange() || _selection.isList()) && ms->hasFormat(mimeStaffListFormat)) {
                ChordRest* cr = 0;
                if (_selection.isRange())
                      cr = _selection.firstChordRest();
                else if (_selection.isSingle()) {
                      Element* e = _selection.element();
                      if (!e->isNote() && !e->isChordRest()) {
                            qDebug("cannot paste to %s", e->name());
                            MScore::setError(DEST_NO_CR);
                            return;
                            }
                      if (e->isNote())
                            e = toNote(e)->chord();
                      cr  = toChordRest(e);
                      }
                if (cr == 0) {
                      MScore::setError(NO_DEST);
                      return;
                      }
                else if (cr->tuplet()) {
                      MScore::setError(DEST_TUPLET);
                      return;
                      }
                else {
                      QByteArray data(ms->data(mimeStaffListFormat));
                      if (MScore::debugMode)
                            qDebug("paste <%s>", data.data());
                      XmlReader e(this, data);
                      e.setPasteMode(true);
                      if (!pasteStaff(e, cr->segment(), cr->staffIdx()))
                            return;
                      }
                }
          else if (ms->hasFormat(mimeSymbolListFormat)) {
                ChordRest* cr = 0;
                if (_selection.isRange())
                      cr = _selection.firstChordRest();
                else if (_selection.isSingle()) {
                      Element* e = _selection.element();
                      if (!e->isNote() && !e->isRest() && !e->isChord()) {
                            qDebug("cannot paste to %s", e->name());
                            MScore::setError(DEST_NO_CR);
                            return;
                            }
                      if (e->isNote())
                            e = toNote(e)->chord();
                      cr  = toChordRest(e);
                      }
                if (cr == 0) {
                      MScore::setError(NO_DEST);
                      return;
                      }
                else if (cr->tuplet()) {
                      MScore::setError(DEST_TUPLET);
                      return;
                      }
                else {
                      QByteArray data(ms->data(mimeSymbolListFormat));
                      if (MScore::debugMode)
                            qDebug("paste <%s>", data.data());
                      XmlReader e(this, data);
                      pasteSymbols(e, cr);
                      }
                }
          else if (ms->hasImage()) {
                QImage im = qvariant_cast<QImage>(ms->imageData());
                QByteArray ba;
                QBuffer buffer(&ba);
                buffer.open(QIODevice::WriteOnly);
                im.save(&buffer, "PNG");

                Image* image = new Image(this);
                image->setImageType(ImageType::RASTER);
                image->loadFromData("dragdrop", ba);

                QList<Element*> els;
                if (_selection.isSingle())
                      els.append(_selection.element());
                else
                      els.append(_selection.elements());

                for (Element* target : els) {
                      Element* nel = image->clone();
                      addRefresh(target->abbox());   // layout() ?!
                      EditData ddata(view);
                      ddata.view       = view;
                      ddata.element    = nel;
                      // ddata.duration   = duration;
                      target->drop(ddata);
                      if (_selection.element())
                            addRefresh(_selection.element()->abbox());
                      }
                delete image;
                }
          else {
                qDebug("cannot paste selState %d staffList %s",
                   int(_selection.state()), (ms->hasFormat(mimeStaffListFormat))? "true" : "false");
                for (const QString& s : ms->formats())
                      qDebug("  format %s", qPrintable(s));
                }
          }
    }

↑ V773 The function was exited without releasing the 'tuplet' pointer. A memory leak is possible.

↑ V668 There is no sense in testing the 'nextSegm' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error.

↑ V547 Expression 'el' is always true.