Audacity 3.2.0
Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
PendingTracks Class Referencefinal

#include <PendingTracks.h>

Inheritance diagram for PendingTracks:
[legend]
Collaboration diagram for PendingTracks:
[legend]

Public Types

using Updater = std::function< void(Track &dest, const Track &src)>
 
- Public Types inherited from Observer::Publisher< TrackListEvent >
using message_type = TrackListEvent
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const TrackListEvent &) >
 Type of functions that can be connected to the Publisher. More...
 

Public Member Functions

 PendingTracks (AudacityProject &project)
 
 PendingTracks (const PendingTracks &)=delete
 
PendingTracksoperator= (const PendingTracks &)=delete
 
 ~PendingTracks ()
 
void RegisterPendingNewTracks (TrackList &&list)
 
ChannelSubstitutePendingChangedChannel (Channel &channel) const
 
const ChannelSubstitutePendingChangedChannel (const Channel &channel) const
 
TrackSubstitutePendingChangedTrack (Track &track) const
 
const TrackSubstitutePendingChangedTrack (const Track &track) const
 
const ChannelSubstituteOriginalChannel (const Channel &channel) const
 
const TrackSubstituteOriginalTrack (const Track &track) const
 
TrackRegisterPendingChangedTrack (Updater updater, Track *src)
 Start a deferred update of the project. More...
 
void UpdatePendingTracks ()
 
void ClearPendingTracks (std::vector< std::shared_ptr< Track > > *pAdded=nullptr)
 Forget pending track additions and changes;. More...
 
bool ApplyPendingTracks ()
 Change the state of the project. More...
 
bool HasPendingTracks () const
 
- Public Member Functions inherited from ClientData::Base
virtual ~Base ()
 
- Public Member Functions inherited from Observer::Publisher< TrackListEvent >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 

Static Public Member Functions

static PendingTracksGet (AudacityProject &project)
 
static const PendingTracksGet (const AudacityProject &project)
 

Private Member Functions

std::pair< Track *, Channel * > DoSubstitutePendingChangedChannel (Track &track, size_t channelIndex) const
 
std::pair< const Track *, const Channel * > DoSubstituteOriginalChannel (const Track &track, size_t channelIndex) const
 

Private Attributes

TrackListmTracks
 
Observer::Subscription mTrackListSubscription
 
std::vector< UpdatermUpdaters
 
std::shared_ptr< TrackListmPendingUpdates
 

Additional Inherited Members

- Static Public Attributes inherited from Observer::Publisher< TrackListEvent >
static constexpr bool notifies_all
 
- Protected Member Functions inherited from Observer::Publisher< TrackListEvent >
CallbackReturn Publish (const TrackListEvent &message)
 Send a message to connected callbacks. More...
 

Detailed Description

Definition at line 23 of file PendingTracks.h.

Member Typedef Documentation

◆ Updater

using PendingTracks::Updater = std::function<void(Track &dest, const Track &src)>

The tracks supplied to this function will have the same number of channels

Definition at line 67 of file PendingTracks.h.

Constructor & Destructor Documentation

◆ PendingTracks() [1/2]

PendingTracks::PendingTracks ( AudacityProject project)
explicit

Definition at line 31 of file PendingTracks.cpp.

34 [this](const TrackListEvent &event){
35 switch (event.mType) {
36 case TrackListEvent::PERMUTED:
37 case TrackListEvent::RESIZING:
38 case TrackListEvent::ADDITION:
39 case TrackListEvent::DELETION:
40 UpdatePendingTracks();
41 break;
42 default:
43 break;
44 }
45 // Pass along to downstream listeners
46 Publish(event);
47 })}
49{}
const auto project
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const TrackListEvent &message)
Send a message to connected callbacks.
Definition: Observer.h:207
TrackList & mTracks
std::shared_ptr< TrackList > mPendingUpdates
Observer::Subscription mTrackListSubscription
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
AudacityProject * GetOwner()
Definition: Track.h:887
static TrackListHolder Temporary(AudacityProject *pProject, const Track::Holder &pTrack={})
Definition: Track.cpp:858
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
Definition: Track.h:803
const Type mType
Definition: Track.h:837

References TrackListEvent::ADDITION, TrackListEvent::DELETION, TrackListEvent::PERMUTED, Observer::Publisher< TrackListEvent >::Publish(), TrackListEvent::RESIZING, and UpdatePendingTracks().

Here is the call graph for this function:

◆ PendingTracks() [2/2]

PendingTracks::PendingTracks ( const PendingTracks )
delete

◆ ~PendingTracks()

PendingTracks::~PendingTracks ( )
default

Member Function Documentation

◆ ApplyPendingTracks()

bool PendingTracks::ApplyPendingTracks ( )

Change the state of the project.

Strong guarantee for project state in case of exceptions. Will always clear the pending updates. Return true if the state of the track list really did change.

Exception safety guarantee:
Strong

Definition at line 227 of file PendingTracks.cpp.

228{
229 std::vector<std::shared_ptr<Track>> additions;
230 auto updated = TrackList::Temporary(mTracks.GetOwner());
231 {
232 // Always clear, even if one of the update functions throws
233 Finally Do{[&]{ ClearPendingTracks(&additions); }};
235 // Clear updaters before any more track list events are processed
236 mUpdaters.clear();
237 updated.swap(mPendingUpdates);
238 }
239
240 bool result = false;
241
242 // Remaining steps must be No-fail-guarantee so that this function
243 // gives Strong-guarantee
244
245 std::vector<std::shared_ptr<Track>> reinstated;
246
247 for (const auto pendingTrack : *updated)
248 pendingTrack->ReparentAllAttachments();
249
250 while (!updated->empty()) {
251 auto iter = updated->begin();
252 auto pendingTrack = *iter;
253 auto src = mTracks.FindById(pendingTrack->GetId());
254 if (src) {
255 mTracks.ReplaceOne(*src, std::move(*updated));
256 result = true;
257 }
258 else {
259 // Perhaps a track marked for pending changes got deleted by
260 // some other action. Recreate it so we don't lose the
261 // accumulated changes.
262 reinstated.push_back(pendingTrack->SharedPointer());
263 updated->Remove(*pendingTrack);
264 }
265 }
266
267 // If there are tracks to reinstate, append them to the list.
268 for (auto &pendingTrack : reinstated)
269 if (pendingTrack)
270 mTracks.Add(move(pendingTrack)), result = true;
271
272 // Put the pending added tracks back into the list, preserving their
273 // positions and assigning ids.
274 auto iter = mTracks.begin();
275 for (auto &pendingTrack : additions) {
276 auto next = iter;
277 ++next;
278 if (pendingTrack)
279 // This emits appropriate track list events
280 mTracks.Insert(*iter, pendingTrack, true);
281 else
282 assert(iter != mTracks.end()); // Deduce that from ClearPendingTrack
283 iter = next;
284 }
285
286 return result;
287}
std::vector< Updater > mUpdaters
void UpdatePendingTracks()
void ClearPendingTracks(std::vector< std::shared_ptr< Track > > *pAdded=nullptr)
Forget pending track additions and changes;.
void Insert(const Track *before, const Track::Holder &pSrc, bool assignIds=false)
Moves *pSrc to position where before is located. If before is nullptr the track is appended.
Definition: Track.cpp:478
iterator end()
Definition: Track.h:906
Track::Holder ReplaceOne(Track &t, TrackList &&with)
Definition: Track.cpp:560
iterator begin()
Definition: Track.h:905
Track * FindById(TrackId id)
Definition: Track.cpp:517
TrackKind * Add(const std::shared_ptr< TrackKind > &t, bool assignIds=true)
Definition: Track.h:1048
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
Definition: MemoryX.h:175

References TrackList::Add(), TrackList::begin(), ClearPendingTracks(), TrackList::end(), TrackList::FindById(), TrackList::GetOwner(), TrackList::Insert(), mPendingUpdates, mTracks, mUpdaters, TrackList::ReplaceOne(), TrackList::Temporary(), and UpdatePendingTracks().

Referenced by ProjectAudioManager::OnCommitRecording().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ClearPendingTracks()

void PendingTracks::ClearPendingTracks ( std::vector< std::shared_ptr< Track > > *  pAdded = nullptr)

Forget pending track additions and changes;.

if requested, give back the pending added tracks, as channel groups, stored in the vector at their original positions in iteration order and nulls corresponding with non-added tracks in original iteration order; no trailing nulls

Exception safety guarantee:
No-fail

Definition at line 197 of file PendingTracks.cpp.

199{
200 mUpdaters.clear();
201 mPendingUpdates->Clear();
202
203 if (pAdded)
204 pAdded->clear();
205
206 auto [it, end] = mTracks.Any();
207 while (it != end) {
208 const auto pTrack = *it;
209 ++it;
210 if (pTrack->GetId() == TrackId{}) {
211 if (pAdded)
212 pAdded->emplace_back(mTracks.Remove(*pTrack));
213 }
214 else {
215 if (pAdded)
216 pAdded->push_back(nullptr);
217 }
218 }
219
220 if (pAdded)
221 // Remove trailing nulls
222 while (!pAdded->empty() && !pAdded->back())
223 pAdded->pop_back();
224}
An in-session identifier of track objects across undo states. It does not persist between sessions.
Definition: Track.h:79
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:950
Track::Holder Remove(Track &track)
Remove a track and return it.
Definition: Track.cpp:584
const char * end(const char *str) noexcept
Definition: StringUtils.h:106

References TrackList::Any(), details::end(), mPendingUpdates, mTracks, mUpdaters, and TrackList::Remove().

Referenced by ApplyPendingTracks(), ProjectAudioManager::CancelRecording(), and AudacityApp::OnExceptionInMainLoop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoSubstituteOriginalChannel()

std::pair< const Track *, const Channel * > PendingTracks::DoSubstituteOriginalChannel ( const Track track,
size_t  channelIndex 
) const
private

Definition at line 116 of file PendingTracks.cpp.

118{
119 auto pTrack = &track;
120 if (!mPendingUpdates->empty()) {
121 const auto end = mPendingUpdates->end();
122 // Find the shadow track with the id
123 const auto pred = [id = track.GetId()](const auto &pTrack){
124 return pTrack->GetId() == id; };
125 if (const auto it =
126 std::find_if(mPendingUpdates->begin(), end, pred); it != end)
127 {
128 const auto end2 = mTracks.end();
129 // Find the original track with the id
130 if (const auto it2 = std::find_if(mTracks.begin(), end2, pred)
131 ; it2 != end2)
132 {
133 pTrack = *it2;
134 // Find the correct corresponding channel
135 const auto &channels = pTrack->Channels();
136 const auto size = channels.size();
137 // This should be provable from how RegisterPendingChangedTrack
138 // constructs the substitutes
139 assert(channelIndex < size);
140
141 auto channelIter = channels.begin();
142 std::advance(channelIter, std::min<int>(channelIndex, size - 1));
143 return { pTrack, (*channelIter).get() };
144 }
145 }
146 }
147 return {};
148}
int id
TrackId GetId() const
Definition: Track.h:136

References TrackList::begin(), TrackList::end(), details::end(), Track::GetId(), id, mPendingUpdates, mTracks, and size.

Referenced by SubstituteOriginalChannel(), and SubstituteOriginalTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoSubstitutePendingChangedChannel()

std::pair< Track *, Channel * > PendingTracks::DoSubstitutePendingChangedChannel ( Track track,
size_t  channelIndex 
) const
private

Definition at line 59 of file PendingTracks.cpp.

61{
62 // Linear search. Tracks in a project are usually very few.
63 auto pTrack = &track;
64 if (!mPendingUpdates->empty()) {
65 const auto end = mPendingUpdates->end();
66 // Find the shadow track with the id
67 const auto pred = [id = track.GetId()](const auto &pTrack){
68 return pTrack->GetId() == id; };
69 if (const auto it = std::find_if(mPendingUpdates->begin(), end, pred)
70 ; it != end)
71 {
72 pTrack = *it;
73 // Find the correct corresponding channel
74 const auto &channels = pTrack->Channels();
75 const auto size = channels.size();
76 // This should be provable from how RegisterPendingChangedTrack
77 // constructs the substitutes
78 assert(channelIndex < size);
79 auto channelIter = channels.begin();
80 std::advance(channelIter, std::min<int>(channelIndex, size - 1));
81 return { pTrack, (*channelIter).get() };
82 }
83 }
84 return {};
85}

References details::end(), Track::GetId(), id, mPendingUpdates, and size.

Referenced by SubstitutePendingChangedChannel(), and SubstitutePendingChangedTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Get() [1/2]

PendingTracks & PendingTracks::Get ( AudacityProject project)
static

◆ Get() [2/2]

const PendingTracks & PendingTracks::Get ( const AudacityProject project)
static

Definition at line 26 of file PendingTracks.cpp.

27{
28 return Get(const_cast<AudacityProject &>(project));
29}
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static PendingTracks & Get(AudacityProject &project)

References Get(), and project.

Here is the call graph for this function:

◆ HasPendingTracks()

bool PendingTracks::HasPendingTracks ( ) const

Definition at line 289 of file PendingTracks.cpp.

290{
291 if (!mPendingUpdates->empty())
292 return true;
293 const auto end = mTracks.end();
294 return (end != std::find_if(mTracks.begin(), end, [](const Track *t){
295 return t->GetId() == TrackId{};
296 }));
297}
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110

References TrackList::begin(), TrackList::end(), details::end(), mPendingUpdates, and mTracks.

Referenced by anonymous_namespace{UndoTracks.cpp}::TrackListRestorer::CanUndoOrRedo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=()

PendingTracks & PendingTracks::operator= ( const PendingTracks )
delete

◆ RegisterPendingChangedTrack()

Track * PendingTracks::RegisterPendingChangedTrack ( Updater  updater,
Track src 
)

Start a deferred update of the project.

The return value is a duplicate of the given track. While ApplyPendingTracks or ClearPendingTracks is not yet called, there may be other direct changes to the project that push undo history. Meanwhile the returned object can accumulate other changes for a deferred push, and temporarily shadow the actual project track for display purposes. The Updater function, if not null, merges state (from the actual project into the pending track) which is not meant to be overridden by the accumulated pending changes. Pending track will have the same TrackId as the actual. Pending changed tracks will not occur in iterations.

Definition at line 168 of file PendingTracks.cpp.

169{
170 auto track =
172
173 mUpdaters.push_back(move(updater));
174 mPendingUpdates->Add(track);
175 return track.get();
176}
static CustomUpdaterValue updater
virtual Holder Duplicate(DuplicateOptions={}) const
public nonvirtual duplication function that invokes Clone()
Definition: Track.cpp:109
Choices when duplicating a track.
Definition: Track.h:271
DuplicateOptions ShallowCopyAttachments() &&
Definition: Track.h:284

References Track::Duplicate(), mPendingUpdates, mUpdaters, Track::DuplicateOptions::ShallowCopyAttachments(), and updater.

Here is the call graph for this function:

◆ RegisterPendingNewTracks()

void PendingTracks::RegisterPendingNewTracks ( TrackList &&  list)

Like RegisterPendingChangedTrack, but for a list of new tracks, not a replacement track.

Caller supplies the list, and there are no updates. Pending tracks will have an unassigned TrackId. Pending new tracks WILL occur in iterations, always after actual tracks, and in the sequence that they were added. They can be distinguished from actual tracks because they have default TrackId.

Definition at line 53 of file PendingTracks.cpp.

54{
55 mTracks.Append(std::move(list), false);
56}
void Append(TrackList &&list, bool assignIds=true)
Remove all tracks from list and put them at the end of this
Definition: Track.cpp:870

References TrackList::Append(), and mTracks.

Here is the call graph for this function:

◆ SubstituteOriginalChannel()

const Channel & PendingTracks::SubstituteOriginalChannel ( const Channel channel) const

If the channel is in a pending changed track, return the corresponding original; else return the channel

Definition at line 150 of file PendingTracks.cpp.

152{
153 const auto pTrack =
154 dynamic_cast<const Track *>(&channel.GetChannelGroup());
155 if (!pTrack)
156 return channel;
157 const auto index = channel.GetChannelIndex();
158 const auto [_, pChannel] = DoSubstituteOriginalChannel(*pTrack, index);
159 return pChannel ? *pChannel : channel;
160}
#define _(s)
Definition: Internat.h:73
ChannelGroup & GetChannelGroup()
Channel object's lifetime is assumed to be nested in its Track's.
Definition: Channel.cpp:43
size_t GetChannelIndex() const
Definition: Channel.cpp:25
std::pair< const Track *, const Channel * > DoSubstituteOriginalChannel(const Track &track, size_t channelIndex) const

References _, DoSubstituteOriginalChannel(), Channel::GetChannelGroup(), and Channel::GetChannelIndex().

Referenced by CommonChannelView::GetMinimizedHeight().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SubstituteOriginalTrack()

const Track & PendingTracks::SubstituteOriginalTrack ( const Track track) const

If the track is a pending changed track, return the corresponding original; else return the track

Definition at line 162 of file PendingTracks.cpp.

163{
164 const auto [pTrack, _] = DoSubstituteOriginalChannel(track, 0);
165 return pTrack ? *pTrack : track;
166}

References _, and DoSubstituteOriginalChannel().

Referenced by SyncLock::IsSyncLockSelected().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SubstitutePendingChangedChannel() [1/2]

Channel & PendingTracks::SubstitutePendingChangedChannel ( Channel channel) const

Find anything registered with TrackList::RegisterPendingChangedTrack and not yet cleared or applied; if no such exists, return the given channel

Definition at line 87 of file PendingTracks.cpp.

88{
89 const auto pTrack = dynamic_cast<Track *>(&channel.GetChannelGroup());
90 if (!pTrack)
91 return channel;
92 const auto index = channel.GetChannelIndex();
93 auto [_, pChannel] = DoSubstitutePendingChangedChannel(*pTrack, index);
94 return pChannel ? *pChannel : channel;
95}
std::pair< Track *, Channel * > DoSubstitutePendingChangedChannel(Track &track, size_t channelIndex) const

References _, DoSubstitutePendingChangedChannel(), Channel::GetChannelGroup(), and Channel::GetChannelIndex().

Referenced by SubstitutePendingChangedChannel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SubstitutePendingChangedChannel() [2/2]

const Channel & PendingTracks::SubstitutePendingChangedChannel ( const Channel channel) const

Definition at line 98 of file PendingTracks.cpp.

99{
100 return SubstitutePendingChangedChannel(const_cast<Channel&>(channel));
101}
Channel & SubstitutePendingChangedChannel(Channel &channel) const

References SubstitutePendingChangedChannel().

Here is the call graph for this function:

◆ SubstitutePendingChangedTrack() [1/2]

const Track & PendingTracks::SubstitutePendingChangedTrack ( const Track track) const

Definition at line 109 of file PendingTracks.cpp.

111{
112 return SubstitutePendingChangedTrack(const_cast<Track&>(track));
113}
Track & SubstitutePendingChangedTrack(Track &track) const

References SubstitutePendingChangedTrack().

Here is the call graph for this function:

◆ SubstitutePendingChangedTrack() [2/2]

Track & PendingTracks::SubstitutePendingChangedTrack ( Track track) const

Find anything registered with TrackList::RegisterPendingChangedTrack and not yet cleared or applied; if no such exists, return the given track

Definition at line 103 of file PendingTracks.cpp.

104{
105 auto [pTrack, _] = DoSubstitutePendingChangedChannel(track, 0);
106 return pTrack ? *pTrack : track;
107}

References _, and DoSubstitutePendingChangedChannel().

Referenced by CloseButtonHandle::CommitChanges(), NoteTrackAffordanceControls::HitTest(), WaveTrackAffordanceControls::HitTest(), and SubstitutePendingChangedTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdatePendingTracks()

void PendingTracks::UpdatePendingTracks ( )

Invoke the updaters of pending tracks. Pass any exceptions from the updater functions.

Definition at line 178 of file PendingTracks.cpp.

179{
180 if (mPendingUpdates->empty())
181 return;
182 auto pUpdater = mUpdaters.begin();
183 for (const auto &pendingTrack : *mPendingUpdates) {
184 auto src = mTracks.FindById(pendingTrack->GetId());
185 // Copy just a part of the track state, according to the update
186 // function
187 const auto &updater = *pUpdater;
188 if (pendingTrack && src) {
189 if (updater)
190 updater(*pendingTrack, *src);
191 }
192 ++pUpdater;
193 }
194}
std::optional< LogWindowUpdater > pUpdater
Definition: LogWindow.cpp:53

References TrackList::FindById(), mPendingUpdates, mTracks, mUpdaters, anonymous_namespace{LogWindow.cpp}::pUpdater, and updater.

Referenced by ApplyPendingTracks(), PendingTracks(), and TrackPanel::ProcessUIHandleResult().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mPendingUpdates

std::shared_ptr<TrackList> PendingTracks::mPendingUpdates
private

◆ mTrackListSubscription

Observer::Subscription PendingTracks::mTrackListSubscription
private

Definition at line 121 of file PendingTracks.h.

◆ mTracks

TrackList& PendingTracks::mTracks
private

◆ mUpdaters

std::vector<Updater> PendingTracks::mUpdaters
private

The documentation for this class was generated from the following files: