MuseScore/libmscore/paste.cpp

542 lines
25 KiB
C++
Raw Normal View History

2012-08-09 12:12:43 +02:00
//=============================================================================
// 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 "utils.h"
#include "key.h"
#include "clef.h"
#include "navigate.h"
#include "slur.h"
#include "note.h"
#include "rest.h"
#include "chord.h"
#include "text.h"
#include "sig.h"
#include "staff.h"
#include "part.h"
#include "style.h"
#include "page.h"
#include "barline.h"
#include "tuplet.h"
#include "xml.h"
#include "ottava.h"
#include "trill.h"
#include "pedal.h"
#include "hairpin.h"
#include "textline.h"
#include "keysig.h"
#include "volta.h"
#include "dynamic.h"
#include "box.h"
#include "harmony.h"
#include "system.h"
#include "stafftext.h"
#include "articulation.h"
#include "layoutbreak.h"
#include "drumset.h"
#include "beam.h"
#include "lyrics.h"
#include "pitchspelling.h"
#include "measure.h"
#include "tempo.h"
#include "sig.h"
#include "undo.h"
#include "timesig.h"
#include "repeat.h"
#include "tempotext.h"
#include "clef.h"
#include "noteevent.h"
#include "breath.h"
#include "tablature.h"
#include "stafftype.h"
#include "segment.h"
#include "chordlist.h"
#include "mscore.h"
#include "accidental.h"
#include "sequencer.h"
//---------------------------------------------------------
// cmdPaste
//---------------------------------------------------------
void Score::cmdPaste(MuseScoreView* view)
{
const QMimeData* ms = QApplication::clipboard()->mimeData();
if (ms == 0) {
qDebug("no application mime data");
return;
}
if (selection().isSingle() && ms->hasFormat(mimeSymbolFormat)) {
QByteArray data(ms->data(mimeSymbolFormat));
2013-01-11 18:10:18 +01:00
XmlReader e(data);
2012-08-09 12:12:43 +02:00
QPointF dragOffset;
Fraction duration(1, 4);
2012-09-13 18:01:34 +02:00
Element::ElementType type = Element::readType(e, &dragOffset, &duration);
if (type != Element::INVALID) {
2012-08-09 12:12:43 +02:00
Element* el = Element::create(type, this);
if (el) {
el->read(e);
addRefresh(selection().element()->abbox()); // layout() ?!
DropData ddata;
ddata.view = view;
ddata.element = el;
ddata.duration = duration;
selection().element()->drop(ddata);
if (selection().element())
addRefresh(selection().element()->abbox());
}
}
else
qDebug("cannot read type");
}
else if ((selection().state() == SEL_RANGE || selection().state() == SEL_LIST)
&& ms->hasFormat(mimeStaffListFormat)) {
ChordRest* cr = 0;
if (selection().state() == SEL_RANGE) {
cr = selection().firstChordRest();
}
else if (selection().isSingle()) {
Element* e = selection().element();
2012-09-13 18:01:34 +02:00
if (e->type() != Element::NOTE && e->type() != Element::REST) {
2012-08-09 12:12:43 +02:00
qDebug("cannot paste to %s", e->name());
return;
}
2012-09-13 18:01:34 +02:00
if (e->type() == Element::NOTE)
2012-08-09 12:12:43 +02:00
e = static_cast<Note*>(e)->chord();
cr = static_cast<ChordRest*>(e);
}
if (cr == 0) {
qDebug("no destination for paste");
return;
}
QByteArray data(ms->data(mimeStaffListFormat));
2013-01-23 14:14:09 +01:00
// qDebug("paste <%s>", data.data());
2013-01-11 18:10:18 +01:00
XmlReader e(data);
pasteStaff(e, cr);
2012-08-09 12:12:43 +02:00
}
else if (ms->hasFormat(mimeSymbolListFormat) && selection().isSingle()) {
qDebug("cannot paste symbol list to element");
}
else {
qDebug("cannot paste selState %d staffList %d",
selection().state(), ms->hasFormat(mimeStaffListFormat));
foreach(const QString& s, ms->formats())
qDebug(" format %s", qPrintable(s));
}
}
//---------------------------------------------------------
// pasteStaff
//---------------------------------------------------------
2013-01-11 18:10:18 +01:00
void Score::pasteStaff(XmlReader& e, ChordRest* dst)
2012-08-09 12:12:43 +02:00
{
static const Segment::SegmentTypes st = Segment::SegChordRest;
for (Segment* s = firstMeasure()->first(st); s; s = s->next1(st)) {
for (Spanner* e = s->spannerFor(); e; e = e->next())
2012-08-09 12:12:43 +02:00
e->setId(-1);
}
int dstStaffStart = dst->staffIdx();
int dstTick = dst->tick();
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
if (e.name() != "StaffList") {
e.unknown();
2013-01-17 12:56:14 +01:00
break;
2012-08-09 12:12:43 +02:00
}
2013-01-11 18:10:18 +01:00
int tickStart = e.intAttribute("tick", 0);
int tickLen = e.intAttribute("len", 0);
int srcStaffStart = e.intAttribute("staff", 0);
int staves = e.intAttribute("staves", 0);
2013-01-21 20:21:41 +01:00
e.setTick(tickStart);
2012-08-09 12:12:43 +02:00
QSet<int> blackList;
for (int i = 0; i < staves; ++i) {
int staffIdx = i + dstStaffStart;
if (staffIdx >= nstaves())
break;
if (!makeGap1(dst->tick(), staffIdx, Fraction::fromTicks(tickLen))) {
qDebug("cannot make gap in staff %d at tick %d", staffIdx, dst->tick());
blackList.insert(staffIdx);
}
}
bool pasted = false;
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
if (e.name() != "Staff") {
e.unknown();
2013-01-17 12:56:14 +01:00
break;
2012-08-09 12:12:43 +02:00
}
2013-01-11 18:10:18 +01:00
int srcStaffIdx = e.attribute("id", "0").toInt();
2013-01-17 12:56:14 +01:00
if (blackList.contains(srcStaffIdx)) {
e.skipCurrentElement();
2012-08-09 12:12:43 +02:00
continue;
2013-01-17 12:56:14 +01:00
}
2012-08-09 12:12:43 +02:00
int dstStaffIdx = srcStaffIdx - srcStaffStart + dstStaffStart;
if (dstStaffIdx >= nstaves())
break;
2013-01-21 20:21:41 +01:00
e.tuplets().clear();
2013-01-11 18:10:18 +01:00
while (e.readNextStartElement()) {
2012-08-09 12:12:43 +02:00
pasted = true;
2013-01-11 18:10:18 +01:00
const QStringRef& tag(e.name());
2012-08-09 12:12:43 +02:00
if (tag == "tick")
2013-01-21 20:21:41 +01:00
e.setTick(e.readInt());
2012-08-09 12:12:43 +02:00
else if (tag == "Tuplet") {
Tuplet* tuplet = new Tuplet(this);
2013-01-21 20:21:41 +01:00
tuplet->setTrack(e.track());
2013-01-11 18:10:18 +01:00
tuplet->read(e);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* measure = tick2measure(tick);
tuplet->setParent(measure);
tuplet->setTick(tick);
2013-01-21 20:21:41 +01:00
e.addTuplet(tuplet);
2012-08-09 12:12:43 +02:00
}
else if (tag == "Slur") {
Slur* slur = new Slur(this);
2013-01-11 18:10:18 +01:00
slur->read(e);
2012-08-09 12:12:43 +02:00
slur->setTrack(dstStaffIdx * VOICES);
2013-01-21 20:21:41 +01:00
e.addSpanner(slur);
2012-08-09 12:12:43 +02:00
}
else if (tag == "Chord" || tag == "Rest" || tag == "RepeatMeasure") {
2013-01-18 10:55:52 +01:00
ChordRest* cr = static_cast<ChordRest*>(Element::name2Element(tag, this));
2013-01-21 20:21:41 +01:00
cr->setTrack(e.track());
2013-01-11 18:10:18 +01:00
cr->read(e);
2012-08-09 12:12:43 +02:00
cr->setSelected(false);
int voice = cr->voice();
int track = dstStaffIdx * VOICES + voice;
cr->setTrack(track);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
e.setTick(e.tick() + cr->actualTicks());
2012-08-09 12:12:43 +02:00
pasteChordRest(cr, tick);
}
else if (tag == "HairPin"
|| tag == "Pedal"
|| tag == "Ottava"
|| tag == "Trill"
|| tag == "TextLine"
|| tag == "Volta") {
2013-01-18 10:55:52 +01:00
Spanner* sp = static_cast<Spanner*>(Element::name2Element(tag, this));
2012-08-09 12:12:43 +02:00
sp->setTrack(dstStaffIdx * VOICES);
2013-01-11 18:10:18 +01:00
sp->read(e);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
Segment* segment = m->undoGetSegment(Segment::SegChordRest, tick);
sp->setStartElement(segment);
sp->setParent(segment);
2013-01-21 20:21:41 +01:00
e.addSpanner(sp);
2012-08-09 12:12:43 +02:00
}
else if (tag == "endSpanner") {
2013-01-11 18:10:18 +01:00
int id = e.intAttribute("id");
2013-01-21 20:21:41 +01:00
Spanner* spanner = e.findSpanner(id);
2013-01-17 12:56:14 +01:00
if (spanner) {
2013-01-21 20:21:41 +01:00
e.spanner().removeOne(spanner);
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
Segment* seg = m->undoGetSegment(Segment::SegChordRest, tick);
2013-01-17 12:56:14 +01:00
spanner->setEndElement(seg);
seg->addSpannerBack(spanner);
undoAddElement(spanner);
if (spanner->type() == Element::OTTAVA) {
Ottava* o = static_cast<Ottava*>(spanner);
2012-08-09 12:12:43 +02:00
int shift = o->pitchShift();
Staff* st = o->staff();
int tick1 = static_cast<Segment*>(o->startElement())->tick();
st->pitchOffsets().setPitchOffset(tick1, shift);
st->pitchOffsets().setPitchOffset(tick, 0);
}
2013-01-17 12:56:14 +01:00
else if (spanner->type() == Element::HAIRPIN) {
Hairpin* hp = static_cast<Hairpin*>(spanner);
2012-08-09 12:12:43 +02:00
updateHairpin(hp);
}
}
2013-01-17 12:56:14 +01:00
e.readNext();
2012-08-09 12:12:43 +02:00
}
else if (tag == "Lyrics") {
Lyrics* lyrics = new Lyrics(this);
2013-01-21 20:21:41 +01:00
lyrics->setTrack(e.track());
2013-01-11 18:10:18 +01:00
lyrics->read(e);
2012-08-09 12:12:43 +02:00
lyrics->setTrack(dstStaffIdx * VOICES);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Segment* segment = tick2segment(tick);
if (segment) {
lyrics->setParent(segment);
undoAddElement(lyrics);
}
else {
delete lyrics;
qDebug("no segment found for lyrics");
}
}
else if (tag == "Harmony") {
Harmony* harmony = new Harmony(this);
2013-01-21 20:21:41 +01:00
harmony->setTrack(e.track());
2013-01-11 18:10:18 +01:00
harmony->read(e);
2012-08-09 12:12:43 +02:00
harmony->setTrack(dstStaffIdx * VOICES);
//transpose
Part* partDest = staff(dstStaffIdx)->part();
Part* partSrc = staff(srcStaffIdx)->part();
Interval intervalDest = partDest->instr()->transpose();
Interval intervalSrc = partSrc->instr()->transpose();
Interval interval = Interval(intervalSrc.diatonic - intervalDest.diatonic, intervalSrc.chromatic - intervalDest.chromatic);
if (!styleB(ST_concertPitch)) {
int rootTpc = transposeTpc(harmony->rootTpc(), interval, false);
int baseTpc = transposeTpc(harmony->baseTpc(), interval, false);
undoTransposeHarmony(harmony, rootTpc, baseTpc);
}
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
Segment* seg = m->undoGetSegment(Segment::SegChordRest, tick);
harmony->setParent(seg);
undoAddElement(harmony);
}
else if (tag == "Dynamic"
|| tag == "Symbol"
|| tag == "FretDiagram"
|| tag == "Marker"
|| tag == "Jump"
|| tag == "Image"
|| tag == "Text"
|| tag == "StaffText"
|| tag == "TempoText"
|| tag == "FiguredBass"
2012-08-09 12:12:43 +02:00
) {
2013-01-18 10:55:52 +01:00
Element* el = Element::name2Element(tag, this);
el->setTrack(dstStaffIdx * VOICES); // a valid track might be necessary for el->read() to work
2012-08-09 12:12:43 +02:00
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
Segment* seg = m->undoGetSegment(Segment::SegChordRest, tick);
2013-01-11 18:10:18 +01:00
el->setParent(seg);
el->read(e);
2012-08-09 12:12:43 +02:00
// 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()
el->setTrack(dstStaffIdx * VOICES);
2013-01-11 18:10:18 +01:00
undoAddElement(el);
2012-08-09 12:12:43 +02:00
}
else if (tag == "Clef") {
Clef* clef = new Clef(this);
2013-01-11 18:10:18 +01:00
clef->read(e);
2012-08-09 12:12:43 +02:00
clef->setTrack(dstStaffIdx * VOICES);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
if (m->tick() && m->tick() == tick)
m = m->prevMeasure();
Segment* segment = m->undoGetSegment(Segment::SegClef, tick);
clef->setParent(segment);
undoAddElement(clef);
}
else if (tag == "Breath") {
Breath* breath = new Breath(this);
2013-01-11 18:10:18 +01:00
breath->read(e);
2012-08-09 12:12:43 +02:00
breath->setTrack(dstStaffIdx * VOICES);
2013-01-21 20:21:41 +01:00
int tick = e.tick() - tickStart + dstTick;
2012-08-09 12:12:43 +02:00
Measure* m = tick2measure(tick);
Segment* segment = m->undoGetSegment(Segment::SegBreath, tick);
breath->setParent(segment);
undoAddElement(breath);
}
else if (tag == "Beam") {
Beam* beam = new Beam(this);
beam->setTrack(e.track());
beam->read(e);
beam->setParent(0);
e.addBeam(beam);
}
2012-08-09 12:12:43 +02:00
else if (tag == "BarLine") {
2013-01-17 12:56:14 +01:00
e.skipCurrentElement(); // ignore bar line
2012-08-09 12:12:43 +02:00
}
2013-01-22 11:42:52 +01:00
else {
qDebug("PasteStaff: element %s not handled", tag.toUtf8().data());
e.skipCurrentElement(); // ignore
}
2012-08-09 12:12:43 +02:00
}
2013-01-21 20:21:41 +01:00
foreach (Tuplet* tuplet, e.tuplets()) {
2012-08-09 12:12:43 +02:00
if (tuplet->elements().isEmpty()) {
// this should not happen and is a sign of input file corruption
qDebug("Measure:pasteStaff(): empty tuplet");
delete tuplet;
}
else {
Measure* measure = tick2measure(tuplet->tick());
tuplet->setParent(measure);
tuplet->sortElements();
}
}
}
if (pasted) { //select only if we pasted something
Segment* s1 = tick2segment(dstTick);
Segment* s2 = tick2segment(dstTick + tickLen);
int endStaff = dstStaffStart + staves;
if (endStaff > nstaves())
endStaff = nstaves();
_selection.setRange(s1, s2, dstStaffStart, endStaff);
_selection.updateSelectedElements();
foreach(MuseScoreView* v, viewer)
v->adjustCanvasPosition(s1, false);
if (selection().state() != SEL_RANGE)
_selection.setState(SEL_RANGE);
}
}
2013-01-21 20:21:41 +01:00
foreach(Spanner* sp, e.spanner()) {
2013-01-09 10:12:03 +01:00
printf(" %s %p %p\n", sp->name(), sp->startElement(), sp->endElement());
if (sp->startElement() == 0 || sp->endElement() == 0) {
// spanner is not copied complete, lets remove it:
printf(" remove\n");
switch(sp->anchor()) {
case Spanner::ANCHOR_SEGMENT:
if (sp->startElement())
static_cast<Segment*>(sp->startElement())->removeSpannerFor(sp);
else if (sp->endElement())
static_cast<Segment*>(sp->endElement())->removeSpannerBack(sp);
break;
case Spanner::ANCHOR_MEASURE:
if (sp->startElement())
static_cast<Measure*>(sp->startElement())->removeSpannerFor(sp);
else if (sp->endElement())
static_cast<Measure*>(sp->endElement())->removeSpannerBack(sp);
break;
break;
case Spanner::ANCHOR_CHORD:
if (sp->startElement())
static_cast<ChordRest*>(sp->startElement())->removeSpannerFor(sp);
else if (sp->endElement())
static_cast<ChordRest*>(sp->endElement())->removeSpannerBack(sp);
break;
case Spanner::ANCHOR_NOTE:
if (sp->startElement())
static_cast<Note*>(sp->startElement())->removeSpannerFor(sp);
else if (sp->endElement())
static_cast<Note*>(sp->endElement())->removeSpannerBack(sp);
break;
}
delete sp;
}
2012-08-09 12:12:43 +02:00
}
connectTies();
}
//---------------------------------------------------------
// pasteChordRest
//---------------------------------------------------------
void Score::pasteChordRest(ChordRest* cr, int tick)
{
// qDebug("pasteChordRest %s at %d", cr->name(), tick);
2012-09-13 18:01:34 +02:00
if (cr->type() == Element::CHORD) {
2012-08-09 12:12:43 +02:00
// set note track
// check if staffMove moves a note to a
// nonexistant staff
//
int track = cr->track();
Chord* c = static_cast<Chord*>(cr);
Part* part = cr->staff()->part();
int nn = (track / VOICES) + c->staffMove();
if (nn < 0 || nn >= nstaves())
c->setStaffMove(0);
if (!styleB(ST_concertPitch) && part->instr()->transpose().chromatic) {
Interval interval = part->instr()->transpose();
if (!interval.isZero()) {
interval.flip();
foreach(Note* n, c->notes()) {
int npitch;
int ntpc;
transposeInterval(n->pitch(), n->tpc(), &npitch, &ntpc, interval, true);
n->setPitch(npitch, ntpc);
}
}
}
}
Measure* measure = tick2measure(tick);
2012-09-13 18:01:34 +02:00
bool isGrace = (cr->type() == Element::CHORD) && (((Chord*)cr)->noteType() != NOTE_NORMAL);
2012-08-09 12:12:43 +02:00
int measureEnd = measure->tick() + measure->ticks();
if (tick >= measureEnd) // end of score
return;
if (!isGrace && (tick + cr->actualTicks() > measureEnd)) {
2012-09-13 18:01:34 +02:00
if (cr->type() == Element::CHORD) {
2012-08-09 12:12:43 +02:00
// split Chord
Chord* c = static_cast<Chord*>(cr);
int rest = c->actualTicks();
int len = measureEnd - tick;
rest -= len;
TDuration d;
d.setVal(len);
c->setDurationType(d);
c->setDuration(d.fraction());
undoAddCR(c, measure, tick);
while (rest) {
tick += c->actualTicks();
measure = tick2measure(tick);
if (measure->tick() != tick) { // last measure
qDebug("==last measure %d != %d", measure->tick(), tick);
break;
}
Chord* c2 = static_cast<Chord*>(c->clone());
len = measure->ticks() > rest ? rest : measure->ticks();
TDuration d;
d.setVal(len);
c2->setDurationType(d);
rest -= len;
undoAddCR(c2, measure, tick);
QList<Note*> nl1 = c->notes();
QList<Note*> nl2 = c2->notes();
for (int 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;
}
}
else {
// split Rest
Rest* r = static_cast<Rest*>(cr);
Fraction rest = r->duration();
while (!rest.isZero()) {
Rest* r2 = static_cast<Rest*>(r->clone());
measure = tick2measure(tick);
Fraction mlen = Fraction::fromTicks(measure->tick() + measure->ticks() - tick);
Fraction len = rest > mlen ? mlen : rest;
r2->setDuration(len);
r2->setDurationType(TDuration(len));
undoAddCR(r2, measure, tick);
rest -= len;
tick += r2->actualTicks();
}
delete r;
}
}
else {
undoAddCR(cr, measure, tick);
}
}
2013-01-23 14:14:09 +01:00