diff options
Diffstat (limited to 'src/commands/edit/PasteEventsCommand.cpp')
-rw-r--r-- | src/commands/edit/PasteEventsCommand.cpp | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/src/commands/edit/PasteEventsCommand.cpp b/src/commands/edit/PasteEventsCommand.cpp new file mode 100644 index 0000000..f6fd323 --- /dev/null +++ b/src/commands/edit/PasteEventsCommand.cpp @@ -0,0 +1,321 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <glaurent@telegraph-road.org>, + Chris Cannam <cannam@all-day-breakfast.com>, + Richard Bown <richard.bown@ferventsoftware.com> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + + +#include "PasteEventsCommand.h" + +#include "misc/Debug.h" +#include "base/Clipboard.h" +#include "base/Event.h" +#include "base/NotationTypes.h" +#include "base/Segment.h" +#include "base/SegmentNotationHelper.h" +#include "document/BasicCommand.h" +#include <qstring.h> +#include "base/BaseProperties.h" + + +namespace Rosegarden +{ + +using namespace BaseProperties; + +PasteEventsCommand::PasteEventsCommand(Segment &segment, + Clipboard *clipboard, + timeT pasteTime, + PasteType pasteType) : + BasicCommand(getGlobalName(), segment, pasteTime, + getEffectiveEndTime(segment, clipboard, pasteTime)), + m_relayoutEndTime(getEndTime()), + m_clipboard(new Clipboard(*clipboard)), + m_pasteType(pasteType), + m_pastedEvents(segment) +{ + if (pasteType != OpenAndPaste) { + + // paste clef or key -> relayout to end + + if (clipboard->isSingleSegment()) { + + Segment *s(clipboard->getSingleSegment()); + for (Segment::iterator i = s->begin(); i != s->end(); ++i) { + if ((*i)->isa(Clef::EventType) || + (*i)->isa(Key::EventType)) { + m_relayoutEndTime = s->getEndTime(); + break; + } + } + } + } +} + +PasteEventsCommand::PasteEventsCommand(Segment &segment, + Clipboard *clipboard, + timeT pasteTime, + timeT pasteEndTime, + PasteType pasteType) : + BasicCommand(getGlobalName(), segment, pasteTime, pasteEndTime), + m_relayoutEndTime(getEndTime()), + m_clipboard(new Clipboard(*clipboard)), + m_pasteType(pasteType), + m_pastedEvents(segment) +{} + +PasteEventsCommand::~PasteEventsCommand() +{ + delete m_clipboard; +} + +PasteEventsCommand::PasteTypeMap + +PasteEventsCommand::getPasteTypes() +{ + static PasteTypeMap types; + static bool haveTypes = false; + if (!haveTypes) { + types[Restricted] = + i18n("Paste into an existing gap [\"restricted\"]"); + types[Simple] = + i18n("Erase existing events to make room [\"simple\"]"); + types[OpenAndPaste] = + i18n("Move existing events out of the way [\"open-n-paste\"]"); + types[NoteOverlay] = + i18n("Overlay notes, tying against present notes [\"note-overlay\"]"); + types[MatrixOverlay] = + i18n("Overlay notes, ignoring present notes [\"matrix-overlay\"]"); + } + return types; +} + +timeT +PasteEventsCommand::getEffectiveEndTime(Segment &segment, + Clipboard *clipboard, + timeT pasteTime) +{ + if (!clipboard->isSingleSegment()) { + RG_DEBUG << "PasteEventsCommand::getEffectiveEndTime: not single segment" << endl; + return pasteTime; + } + + RG_DEBUG << "PasteEventsCommand::getEffectiveEndTime: clipboard " + << clipboard->getSingleSegment()->getStartTime() + << " -> " + << clipboard->getSingleSegment()->getEndTime() << endl; + + timeT d = clipboard->getSingleSegment()->getEndTime() - + clipboard->getSingleSegment()->getStartTime(); + + if (m_pasteType == OpenAndPaste) { + return segment.getEndTime() + d; + } else { + Segment::iterator i = segment.findTime(pasteTime + d); + if (i == segment.end()) + return segment.getEndTime(); + else + return (*i)->getAbsoluteTime(); + } +} + +timeT +PasteEventsCommand::getRelayoutEndTime() +{ + return m_relayoutEndTime; +} + +bool +PasteEventsCommand::isPossible() +{ + if (m_clipboard->isEmpty() || !m_clipboard->isSingleSegment()) { + return false; + } + + if (m_pasteType != Restricted) { + return true; + } + + Segment *source = m_clipboard->getSingleSegment(); + + timeT pasteTime = getStartTime(); + timeT origin = source->getStartTime(); + timeT duration = source->getEndTime() - origin; + + RG_DEBUG << "PasteEventsCommand::isPossible: paste time is " << pasteTime << ", origin is " << origin << ", duration is " << duration << endl; + + SegmentNotationHelper helper(getSegment()); + return helper.removeRests(pasteTime, duration, true); +} + +void +PasteEventsCommand::modifySegment() +{ + RG_DEBUG << "PasteEventsCommand::modifySegment" << endl; + + if (!m_clipboard->isSingleSegment()) + return ; + + Segment *source = m_clipboard->getSingleSegment(); + + timeT pasteTime = getStartTime(); + timeT origin = source->getStartTime(); + timeT duration = source->getEndTime() - origin; + + Segment *destination(&getSegment()); + SegmentNotationHelper helper(*destination); + + RG_DEBUG << "PasteEventsCommand::modifySegment() : paste type = " + << m_pasteType << " - pasteTime = " + << pasteTime << " - origin = " << origin << endl; + + // First check for group IDs, which we want to make unique in the + // copies in the destination segment + + std::map<long, long> groupIdMap; + for (Segment::iterator i = source->begin(); i != source->end(); ++i) { + long groupId = -1; + if ((*i)->get + <Int>(BEAMED_GROUP_ID, groupId)) { + if (groupIdMap.find(groupId) == groupIdMap.end()) { + groupIdMap[groupId] = destination->getNextId(); + } + } + } + + switch (m_pasteType) { + + // Do some preliminary work to make space or whatever; + // we do the actual paste after this switch statement + // (except where individual cases do the work and return) + + case Restricted: + if (!helper.removeRests(pasteTime, duration)) + return ; + break; + + case Simple: + destination->erase(destination->findTime(pasteTime), + destination->findTime(pasteTime + duration)); + break; + + case OpenAndPaste: { + std::vector<Event *> copies; + for (Segment::iterator i = destination->findTime(pasteTime); + i != destination->end(); ++i) { + Event *e = (*i)->copyMoving(duration); + if (e->has(BEAMED_GROUP_ID)) { + e->set + <Int>(BEAMED_GROUP_ID, groupIdMap[e->get + <Int>(BEAMED_GROUP_ID)]); + } + copies.push_back(e); + } + + destination->erase(destination->findTime(pasteTime), + destination->end()); + + for (unsigned int i = 0; i < copies.size(); ++i) { + destination->insert(copies[i]); + m_pastedEvents.addEvent(copies[i]); + } + + break; + } + + case NoteOverlay: + for (Segment::iterator i = source->begin(); i != source->end(); ++i) { + if ((*i)->isa(Note::EventRestType)) + continue; + Event *e = (*i)->copyMoving(pasteTime - origin); + if (e->has(BEAMED_GROUP_ID)) { + e->set<Int>(BEAMED_GROUP_ID, + groupIdMap[e->get<Int>(BEAMED_GROUP_ID)]); + } + if ((*i)->isa(Note::EventType)) { + // e is model event: we retain ownership of it + Segment::iterator i = helper.insertNote(e); + delete e; + if (i != destination->end()) m_pastedEvents.addEvent(*i); + } else { + destination->insert(e); + m_pastedEvents.addEvent(e); + } + } + + return ; + + case MatrixOverlay: + + for (Segment::iterator i = source->begin(); i != source->end(); ++i) { + + if ((*i)->isa(Note::EventRestType)) + continue; + + Event *e = (*i)->copyMoving(pasteTime - origin); + + if (e->has(BEAMED_GROUP_TYPE) && + e->get + <String>(BEAMED_GROUP_TYPE) == GROUP_TYPE_BEAMED) { + e->unset(BEAMED_GROUP_ID); + e->unset(BEAMED_GROUP_TYPE); + } + + if (e->has(BEAMED_GROUP_ID)) { + e->set + <Int>(BEAMED_GROUP_ID, groupIdMap[e->get + <Int>(BEAMED_GROUP_ID)]); + } + + destination->insert(e); + m_pastedEvents.addEvent(e); + } + + destination->normalizeRests + (source->getStartTime(), source->getEndTime()); + + return ; + } + + RG_DEBUG << "PasteEventsCommand::modifySegment() - inserting\n"; + + for (Segment::iterator i = source->begin(); i != source->end(); ++i) { + Event *e = (*i)->copyMoving(pasteTime - origin); + if (e->has(BEAMED_GROUP_ID)) { + e->set + <Int>(BEAMED_GROUP_ID, groupIdMap[e->get + <Int>(BEAMED_GROUP_ID)]); + } + destination->insert(e); + m_pastedEvents.addEvent(e); + } + + destination->normalizeRests + (source->getStartTime(), source->getEndTime()); +} + +EventSelection +PasteEventsCommand::getPastedEvents() +{ + return m_pastedEvents; +} + +} |