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