1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "ViewSegment.h"
17 #include "base/Profiler.h"
18
19 #include <QtGlobal>
20
21 namespace Rosegarden
22 {
23
ViewSegment(Segment & t)24 ViewSegment::ViewSegment(Segment &t) :
25 m_segment(t),
26 m_viewElementList(nullptr)
27 {
28 // empty
29 }
30
~ViewSegment()31 ViewSegment::~ViewSegment()
32 {
33 if (m_viewElementList) m_segment.removeObserver(this);
34 notifySourceDeletion();
35 delete m_viewElementList;
36 }
37
38 ViewElementList *
getViewElementList()39 ViewSegment::getViewElementList()
40 {
41 if (!m_viewElementList) {
42
43 m_viewElementList = new ViewElementList;
44
45 for (Segment::const_iterator i = m_segment.begin(); i != m_segment.end(); ++i) {
46
47 if (!wrapEvent(*i)) continue;
48
49 ViewElement *el = makeViewElement(*i);
50 m_viewElementList->insert(el);
51 }
52
53 m_segment.addObserver(this);
54 }
55
56 return m_viewElementList;
57 }
58
59 bool
wrapEvent(Event * e)60 ViewSegment::wrapEvent(Event *e)
61 {
62 timeT emt = m_segment.getEndMarkerTime();
63 return
64 (e->getAbsoluteTime() < emt) ||
65 (e->getAbsoluteTime() == emt && e->getDuration() == 0);
66 }
67
68 ViewElementList::iterator
findEvent(Event * e)69 ViewSegment::findEvent(Event *e)
70 {
71 // Note that we have to create this using the virtual
72 // makeViewElement, because the result of equal_range depends on
73 // the value of the view absolute time for the element, which
74 // depends on the particular subclass of ViewElement in use.
75
76 // (This is also why this method has to be here and not in
77 // ViewElementList -- ViewElementList has no equivalent of
78 // makeViewElement.)
79
80 ViewElement *dummy = makeViewElement(e);
81
82 std::pair<ViewElementList::iterator,
83 ViewElementList::iterator>
84 r = m_viewElementList->equal_range(dummy);
85
86 delete dummy;
87
88 for (ViewElementList::iterator i = r.first; i != r.second; ++i) {
89 if ((*i)->event() == e) {
90 return i;
91 }
92 }
93
94 return m_viewElementList->end();
95 }
96
97 void
eventAdded(const Segment * t,Event * e)98 ViewSegment::eventAdded(const Segment *t, Event *e)
99 {
100 Profiler profiler("ViewSegment::eventAdded");
101 Q_ASSERT(t == &m_segment);
102 (void)t; // avoid warnings
103
104 if (wrapEvent(e)) {
105 ViewElement *el = makeViewElement(e);
106 m_viewElementList->insert(el);
107 notifyAdd(el);
108 }
109 }
110
111 void
eventRemoved(const Segment * t,Event * e)112 ViewSegment::eventRemoved(const Segment *t, Event *e)
113 {
114 Profiler profiler("ViewSegment::eventRemoved");
115 Q_ASSERT(t == &m_segment);
116 (void)t; // avoid warnings
117
118 // If we have it, lose it
119
120 ViewElementList::iterator i = findEvent(e);
121 if (i != m_viewElementList->end()) {
122 notifyRemove(*i);
123 m_viewElementList->erase(i);
124 return;
125 }
126
127 // std::cerr << "Event at " << e->getAbsoluteTime() << ", notation time " << e->getNotationAbsoluteTime() << ", type " << e->getType()
128 // << " not found in ViewSegment" << std::endl;
129 }
130
131 void
endMarkerTimeChanged(const Segment * segment,bool shorten)132 ViewSegment::endMarkerTimeChanged(const Segment *segment, bool shorten)
133 {
134 Segment *s = const_cast<Segment *>(segment);
135
136 Q_ASSERT(s == &m_segment);
137
138 if (shorten) {
139
140 m_viewElementList->erase
141 (m_viewElementList->findTime(s->getEndMarkerTime()),
142 m_viewElementList->end());
143
144 } else {
145
146 timeT myLastEltTime = s->getStartTime();
147 if (m_viewElementList->end() != m_viewElementList->begin()) {
148 ViewElementList::iterator i = m_viewElementList->end();
149 myLastEltTime = (*--i)->event()->getAbsoluteTime();
150 }
151
152 for (Segment::iterator j = s->findTime(myLastEltTime);
153 s->isBeforeEndMarker(j); ++j) {
154
155 ViewElementList::iterator newi = findEvent(*j);
156 if (newi == m_viewElementList->end()) {
157 if (wrapEvent(*j)) {
158 m_viewElementList->insert(makeViewElement(*j));
159 }
160 }
161 }
162 }
163 }
164 void
segmentDeleted(const Segment * s)165 ViewSegment::segmentDeleted(const Segment *s)
166 {
167 Q_ASSERT(s == &m_segment);
168 (void)s; // avoid warnings
169 /*
170 std::cerr << "WARNING: ViewSegment notified of segment deletion: this is probably a bug "
171 << "(ViewSegment should have been deleted before Segment)" << std::endl;
172 */
173 }
174
175 void
notifyAdd(ViewElement * e) const176 ViewSegment::notifyAdd(ViewElement *e) const
177 {
178 Profiler profiler("ViewSegment::notifyAdd");
179 for (ObserverSet::const_iterator i = m_observers.begin();
180 i != m_observers.end(); ++i) {
181 (*i)->elementAdded(this, e);
182 }
183 }
184
185 void
notifyRemove(ViewElement * e) const186 ViewSegment::notifyRemove(ViewElement *e) const
187 {
188 Profiler profiler("ViewSegment::notifyRemove");
189 for (ObserverSet::const_iterator i = m_observers.begin();
190 i != m_observers.end(); ++i) {
191 (*i)->elementRemoved(this, e);
192 }
193 }
194
195 void
notifySourceDeletion() const196 ViewSegment::notifySourceDeletion() const
197 {
198 for (ObserverSet::const_iterator i = m_observers.begin();
199 i != m_observers.end(); ++i) {
200 (*i)->viewSegmentDeleted(this);
201 }
202 }
203
204
205 }
206