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 #include "PasteToTriggerSegmentCommand.h"
20 
21 #include "base/Event.h"
22 #include "misc/Strings.h"
23 #include "misc/Debug.h"
24 #include "base/Clipboard.h"
25 #include "base/Composition.h"
26 #include "base/NotationTypes.h"
27 #include "base/Segment.h"
28 #include "base/TriggerSegment.h"
29 #include <QString>
30 
31 
32 namespace Rosegarden
33 {
34 
35 /** PasteToTriggerSegmentCommand itself **/
36 
37 /**
38    PasteToTriggerSegmentCommand delegates essentially all of its work
39    to PasteToTriggerSegmentWorker so that its code can be shared with
Q_DECLARE_TR_FUNCTIONS(Rosegarden::ChangeStyleCommand)40    CutToTriggerSegmentCommand, which can't be neatly derived from
41    PasteToTriggerSegmentCommand.
42  */
43 
44 PasteToTriggerSegmentCommand::
45 PasteToTriggerSegmentCommand(Composition *composition,
46                              Clipboard *clipboard,
47                              QString label,
48                              int basePitch,
49                              int baseVelocity) :
50     NamedCommand(tr("Paste as New Triggered Segment")),
51     m_worker(composition, new Clipboard(*clipboard),
52              label, basePitch, baseVelocity)
53 {
54     // nothing else
55 }
56 
57 PasteToTriggerSegmentCommand::
58 ~PasteToTriggerSegmentCommand()
59 {}
60 
61 void
62 PasteToTriggerSegmentCommand::execute()
63 { m_worker.execute(); }
64 
65 void
66 PasteToTriggerSegmentCommand::unexecute()
67 { m_worker.unexecute(); }
68 
69 /** PasteToTriggerSegmentWorker **/
70 
71 
72 PasteToTriggerSegmentWorker::PasteToTriggerSegmentWorker(Composition *composition,
73         Clipboard *clipboard,
74         QString label,
75         int basePitch,
76         int baseVelocity) :
77         m_composition(composition),
78         m_clipboard(clipboard ? clipboard : new Clipboard),
79         m_label(label),
80         m_basePitch(basePitch),
81         m_baseVelocity(baseVelocity),
82         m_segment(nullptr),
83         m_detached(false)
84 {
85     // nothing else
86 }
87 
88 PasteToTriggerSegmentWorker::
89 PasteToTriggerSegmentWorker(Composition *composition,
90                             const EventSelection * selection,
91                             QString label,
92                             int basePitch,
93                             int baseVelocity) :
94         m_composition(composition),
95         m_clipboard(new Clipboard),
96         m_label(label),
97         m_basePitch(basePitch),
98         m_baseVelocity(baseVelocity),
99         m_segment(nullptr),
100         m_detached(false)
101 {
102     m_clipboard->newSegment(selection);
103 }
104 
105 PasteToTriggerSegmentWorker::~PasteToTriggerSegmentWorker()
106 {
107     if (m_detached)
108         delete m_segment;
109     delete m_clipboard;
110 }
111 
112 void
113 PasteToTriggerSegmentWorker::execute()
114 {
115     RG_DEBUG << "PasteToTriggerSegmentWorker::execute()";
116 
117     if (m_segment) {
118         // Not the first time executing.
119 
120         RG_DEBUG << " - m_segment == TRUE";
121 
122         m_composition->addTriggerSegment(m_segment, m_id, m_basePitch, m_baseVelocity);
123 
124     } else {
125         // The first time executing, so get values for m_segment,
126         // m_id.
127 
128         RG_DEBUG << " - m_segment == FALSE";
129 
130         if (m_clipboard->isEmpty()) {
131             RG_DEBUG << " - Here's your problem.  The clipboard is empty.";
132             return ;
133         }
134 
135         m_segment = new Segment();
136 
137         RG_DEBUG << " - making a new m_segment";
138 
139         timeT earliestStartTime = 0;
140         timeT latestEndTime = 0;
141 
142         for (Clipboard::iterator i = m_clipboard->begin();
143                 i != m_clipboard->end(); ++i) {
144 
145             if (i == m_clipboard->begin() ||
146                     (*i)->getStartTime() < earliestStartTime) {
147                 earliestStartTime = (*i)->getStartTime();
148             }
149 
150             if ((*i)->getEndMarkerTime() > latestEndTime)
151                 latestEndTime = (*i)->getEndMarkerTime();
152         }
153 
154         for (Clipboard::iterator i = m_clipboard->begin();
155                 i != m_clipboard->end(); ++i) {
156 
157             for (Segment::iterator si = (*i)->begin();
158                     (*i)->isBeforeEndMarker(si); ++si) {
159                 if (!(*si)->isa(Note::EventRestType)) {
160                     m_segment->insert
161                     (new Event(**si,
162                                (*si)->getAbsoluteTime() - earliestStartTime));
163                 }
164             }
165         }
166 
167         if (m_label == "" && m_clipboard->isSingleSegment()) {
168             m_segment->setLabel(m_clipboard->getSingleSegment()->getLabel());
169         }
170         else {
171             m_segment->setLabel(qstrtostr(m_label));
172         }
173 
174         TriggerSegmentRec *rec =
175             m_composition->addTriggerSegment(m_segment, m_basePitch, m_baseVelocity);
176         if (rec)
177             m_id = rec->getId();
178     }
179 
180     m_composition->getTriggerSegmentRec(m_id)->updateReferences();
181 
182     m_detached = false;
183 }
184 
185 void
186 PasteToTriggerSegmentWorker::unexecute()
187 {
188     if (m_segment)
189         m_composition->detachTriggerSegment(m_id);
190     m_detached = true;
191 }
192 
193 }
194