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