1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A MIDI and audio sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7
8 Other copyrights also apply to some parts of this work. Please
9 see the AUTHORS file and individual file headers for details.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version. See the file
15 COPYING included with this distribution for more information.
16 */
17
18
19 #define RG_MODULE_STRING "[MoveCommand]"
20
21 #include "MoveCommand.h"
22
23 #include "misc/Debug.h"
24 #include "base/Event.h"
25 #include "base/NotationTypes.h"
26 #include "base/Segment.h"
27 #include "base/SegmentNotationHelper.h"
28 #include "base/Selection.h"
29 #include "document/BasicCommand.h"
30 #include <QString>
31
32
33 namespace Rosegarden
34 {
35
MoveCommand(Segment & s,timeT delta,bool useNotationTimings,EventSelection & sel)36 MoveCommand::MoveCommand(Segment &s, timeT delta, bool useNotationTimings,
37 EventSelection &sel) :
38 BasicCommand(getGlobalName(), s,
39 delta < 0 ? sel.getStartTime() + delta : sel.getStartTime(),
40 delta < 0 ? sel.getEndTime() + 1 : sel.getEndTime() + 1 + delta,
41 true),
42 m_selection(&sel),
43 m_delta(delta),
44 m_useNotationTimings(useNotationTimings),
45 m_lastInsertedEvent(nullptr)
46 {
47 // nothing else
48 }
49
50 QString
getGlobalName(timeT delta)51 MoveCommand::getGlobalName(timeT delta)
52 {
53 if (delta == 0) {
54 return tr("&Move Events");
55 } else if (delta < 0) {
56 return tr("&Move Events Back");
57 } else {
58 return tr("&Move Events Forward");
59 }
60 }
61
62 void
modifySegment()63 MoveCommand::modifySegment()
64 {
65 RG_DEBUG << "MoveCommand::modifySegment: delta is " << m_delta
66 << ", useNotationTimings " << m_useNotationTimings
67 << ", start time " << m_selection->getStartTime()
68 << ", end time " << m_selection->getEndTime();
69
70 std::vector<Event *> toErase;
71 std::vector<Event *> toInsert;
72
73 timeT a0 = m_selection->getStartTime();
74 timeT a1 = m_selection->getEndTime();
75 timeT b0 = a0 + m_delta;
76 timeT b1 = b0 + (a1 - a0);
77
78 EventSelection::eventcontainer::iterator i;
79
80 for (i = m_selection->getSegmentEvents().begin();
81 i != m_selection->getSegmentEvents().end(); ++i) {
82
83 RG_DEBUG << "MoveCommand::modifySegment: event at " << (*i)->getAbsoluteTime() << " type " << (*i)->getType();
84
85 if ((*i)->isa(Note::EventRestType)) continue;
86
87 toErase.push_back(*i);
88 timeT newTime =
89 (m_useNotationTimings ?
90 (*i)->getNotationAbsoluteTime() : (*i)->getAbsoluteTime()) + m_delta;
91
92 Event *e;
93 if (m_useNotationTimings) {
94 e = new Event(**i, newTime, (*i)->getDuration(), (*i)->getSubOrdering(),
95 newTime, (*i)->getNotationDuration());
96 } else {
97 e = new Event(**i, newTime);
98 }
99
100 toInsert.push_back(e);
101 }
102
103 Segment &segment(m_selection->getSegment());
104
105 for (size_t j = 0; j < toErase.size(); ++j) {
106 Segment::iterator jtr(segment.findSingle(toErase[j]));
107 if (jtr != segment.end()) {
108 RG_DEBUG << "found event " << j;
109 segment.erase(jtr);
110 } else {
111 RG_DEBUG << "failed to find event " << j;
112 }
113 }
114
115 for (size_t j = 0; j < toInsert.size(); ++j) {
116
117 Segment::iterator jtr = segment.end();
118
119 // somewhat like the NoteOverlay part of PasteEventsCommand::modifySegment
120 /* nah -- let's do a de-counterpoint afterwards perhaps
121 if (m_useNotationTimings && toInsert[j]->isa(Note::EventType)) {
122 long pitch = 0;
123 Accidental explicitAccidental = NoAccidental;
124 toInsert[j]->get<String>(ACCIDENTAL, explicitAccidental);
125 if (toInsert[j]->get<Int>(PITCH, pitch)) {
126 jtr = SegmentNotationHelper(segment).insertNote
127 (toInsert[j]->getAbsoluteTime(),
128 Note::getNearestNote(toInsert[j]->getDuration()),
129 pitch, explicitAccidental);
130 delete toInsert[j];
131 toInsert[j] = *jtr;
132 }
133 } else {
134 */
135 jtr = segment.insert(toInsert[j]);
136 // }
137
138 // insert new event back into selection
139 m_selection->addEvent(toInsert[j]);
140
141 if (jtr != segment.end())
142 m_lastInsertedEvent = toInsert[j];
143 }
144
145 if (m_useNotationTimings) {
146 SegmentNotationHelper(segment).deCounterpoint(b0, b1);
147 }
148
149 segment.normalizeRests(a0, a1);
150 segment.normalizeRests(b0, b1);
151 }
152
153 }
154