1
0
mirror of https://github.com/cookiengineer/audacity synced 2026-02-08 04:32:00 +01:00

Revert "Preliminaries to support better interaction of undo and recording"

This reverts commit 6e75ae58ac, reversing
changes made to 714d53e00f.
This commit is contained in:
Paul Licameli
2018-01-14 21:36:33 -05:00
parent 950898dcb9
commit 4ef8da8f16
15 changed files with 192 additions and 721 deletions

View File

@@ -82,8 +82,6 @@ Track::Track(const Track &orig)
// Copy all the track properties except the actual contents
void Track::Init(const Track &orig)
{
mId = orig.mId;
mDefaultName = orig.mDefaultName;
mName = orig.mName;
@@ -155,22 +153,6 @@ int Track::GetY() const
}
void Track::SetY(int y)
{
auto pList = mList.lock();
if (pList && !pList->mPendingUpdates.empty()) {
auto orig = pList->FindById( GetId() );
if (orig && orig != this) {
// delegate, and rely on the update to copy back
orig->SetY(y);
pList->UpdatePendingTracks();
return;
}
}
DoSetY(y);
}
void Track::DoSetY(int y)
{
mY = y;
}
@@ -186,29 +168,14 @@ int Track::GetHeight() const
void Track::SetHeight(int h)
{
mHeight = h;
auto pList = mList.lock();
if (pList && !pList->mPendingUpdates.empty()) {
auto orig = pList->FindById( GetId() );
if (orig && orig != this) {
// delegate, and rely on RecalcPositions to copy back
orig->SetHeight(h);
return;
}
}
DoSetHeight(h);
if (pList) {
pList->RecalcPositions(mNode);
pList->ResizingEvent(mNode);
}
}
void Track::DoSetHeight(int h)
{
mHeight = h;
}
bool Track::GetMinimized() const
{
return mMinimized;
@@ -217,53 +184,23 @@ bool Track::GetMinimized() const
void Track::SetMinimized(bool isMinimized)
{
auto pList = mList.lock();
if (pList && !pList->mPendingUpdates.empty()) {
auto orig = pList->FindById( GetId() );
if (orig && orig != this) {
// delegate, and rely on RecalcPositions to copy back
orig->SetMinimized(isMinimized);
return;
}
}
DoSetMinimized(isMinimized);
mMinimized = isMinimized;
if (pList) {
pList->RecalcPositions(mNode);
pList->ResizingEvent(mNode);
}
}
void Track::DoSetMinimized(bool isMinimized)
{
mMinimized = isMinimized;
}
void Track::SetLinked(bool l)
{
auto pList = mList.lock();
if (pList && !pList->mPendingUpdates.empty()) {
auto orig = pList->FindById( GetId() );
if (orig && orig != this) {
// delegate, and rely on RecalcPositions to copy back
orig->SetLinked(l);
return;
}
}
DoSetLinked(l);
mLinked = l;
if (pList) {
pList->RecalcPositions(mNode);
pList->ResizingEvent(mNode);
}
}
void Track::DoSetLinked(bool l)
{
mLinked = l;
}
Track *Track::GetLink() const
{
auto pList = mList.lock();
@@ -272,16 +209,20 @@ Track *Track::GetLink() const
if (!pList->isNull(mNode)) {
if (mLinked) {
auto next = pList->getNext( mNode );
if ( !pList->isNull( next ) )
auto next = mNode;
++next;
if (!pList->isNull(next)) {
return next->get();
}
}
auto prev = pList->getPrev( mNode );
if ( !pList->isNull( prev ) ) {
if (pList->hasPrev(mNode)) {
auto prev = mNode;
--prev;
auto track = prev->get();
if (track && track->GetLinked())
if (track && track->GetLinked()) {
return track;
}
}
}
@@ -391,7 +332,7 @@ TrackListIterator::TrackListIterator(TrackList * val)
, cur{}
{
if (l)
cur = l->getBegin();
cur = l->ListOfTracks::begin();
}
Track *TrackListIterator::StartWith(Track * val)
@@ -421,13 +362,13 @@ Track *TrackListIterator::First(TrackList * val)
return NULL;
}
cur = l->getBegin();
cur = l->ListOfTracks::begin();
if (!l->isNull(cur)) {
return cur->get();
}
return nullptr;
return NULL;
}
Track *TrackListIterator::Last(bool skiplinked)
@@ -436,19 +377,18 @@ Track *TrackListIterator::Last(bool skiplinked)
return NULL;
}
cur = l->getPrev( l->getEnd() );
if ( l->isNull( cur ) )
return nullptr;
cur = l->ListOfTracks::end();
if (l->hasPrev(cur))
--cur;
else
return NULL;
// With skiplinked set, we won't return the second channel of a linked pair
if (skiplinked) {
auto prev = l->getPrev( cur );
if ( !l->isNull( prev ) &&
!(*cur)->GetLinked() &&
(*cur)->GetLink()
)
cur = prev;
}
if (skiplinked &&
l->hasPrev(cur) &&
!(*cur)->GetLinked() &&
(*cur)->GetLink())
--cur;
return cur->get();
}
@@ -463,24 +403,27 @@ Track *TrackListIterator::Next(bool skipLinked)
return nullptr;
if (skipLinked &&
(*cur)->GetLinked())
cur = l->getNext( cur );
(*cur)->GetLinked()) {
++cur;
}
#ifdef DEBUG_TLI // if we are debugging this bit
wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after skipping linked tracks.")); // check that cur is in the list
#endif
if (!l->isNull(cur))
cur = l->getNext( cur );
if (!l->isNull(cur)) {
++cur;
}
#ifdef DEBUG_TLI // if we are debugging this bit
wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after moving to next track.")); // check that cur is in the list if it is not null
#endif
if (!l->isNull(cur))
if (!l->isNull(cur)) {
return cur->get();
}
return nullptr;
return NULL;
}
Track *TrackListIterator::Prev(bool skiplinked)
@@ -488,13 +431,17 @@ Track *TrackListIterator::Prev(bool skiplinked)
if (!l || l->isNull(cur))
return nullptr;
cur = l->getPrev( cur );
if ( l->isNull( cur ) )
if (!l->hasPrev(cur)) {
l->setNull(cur);
return nullptr;
}
if ( skiplinked ) {
auto prev = l->getPrev( cur );
if( !l->isNull( prev ) && (*prev)->GetLinked() )
--cur;
if (skiplinked && l->hasPrev(cur)) {
auto prev = cur;
--prev;
if ((*prev)->GetLinked())
cur = prev;
}
@@ -511,19 +458,20 @@ Track *TrackListIterator::operator *() const
Track *TrackListIterator::RemoveCurrent()
{
if ( !l || l->isNull( cur ) )
if (!l || l->isNull(cur))
return nullptr;
cur = l->Remove( cur->get() );
cur = l->Remove(cur->get());
#ifdef DEBUG_TLI // if we are debugging this bit
wxASSERT_MSG((!cur || (*l).Contains((*cur).t)), wxT("cur invalid after deletion of track.")); // check that cur is in the list
#endif
if ( !l->isNull( cur ) )
if (!l->isNull(cur)) {
return cur->get();
}
return nullptr;
return NULL;
}
bool TrackListIterator::operator == (const TrackListIterator &other) const
@@ -546,7 +494,7 @@ Track *TrackListCondIterator::StartWith(Track *val)
Track *t = TrackListIterator::StartWith(val);
if (t && !this->Condition(t))
return nullptr;
return NULL;
return t;
}
@@ -707,11 +655,11 @@ Track *SyncLockedTracksIterator::Next(bool skiplinked)
Track *t = TrackListIterator::Next(skiplinked);
if (!t)
return nullptr;
return NULL;
if ( ! IsGoodNextTrack(t) ) {
cur = l->getEnd();
return nullptr;
l->setNull(cur);
return NULL;
}
mInLabelSection = ( t->GetKind() == Track::Label );
@@ -729,19 +677,19 @@ Track *SyncLockedTracksIterator::Prev(bool skiplinked)
// Beginning of tracks
if (!t)
return nullptr;
return NULL;
const bool isLabel = ( t->GetKind() == Track::Label );
const bool isSyncLockable = IsSyncLockableNonLabelTrack( t );
if ( !( isLabel || isSyncLockable ) ) {
cur = l->getEnd();
return nullptr;
l->setNull(cur);
return NULL;
}
if ( !mInLabelSection && isLabel ) {
cur = l->getEnd();
return nullptr;
l->setNull(cur);
return NULL;
}
mInLabelSection = isLabel;
@@ -751,8 +699,8 @@ Track *SyncLockedTracksIterator::Prev(bool skiplinked)
Track *SyncLockedTracksIterator::Last(bool skiplinked)
{
if ( !l || l->isNull( cur ) )
return nullptr;
if (!l || l->isNull(cur))
return NULL;
Track *t = cur->get();
@@ -776,9 +724,6 @@ DEFINE_EVENT_TYPE(EVT_TRACKLIST_PERMUTED);
DEFINE_EVENT_TYPE(EVT_TRACKLIST_RESIZING);
DEFINE_EVENT_TYPE(EVT_TRACKLIST_DELETION);
// same value as in the default constructed TrackId:
long TrackList::mCounter = -1;
TrackList::TrackList()
: wxEvtHandler()
{
@@ -812,39 +757,20 @@ TrackList &TrackList::operator= (TrackList &&that)
void TrackList::DoAssign(const TrackList &that)
{
auto copyLOT = [](
ListOfTracks &dst, const std::weak_ptr< TrackList > &self,
const ListOfTracks &src )
{
for (const auto &ptr : src)
dst.push_back(
ListOfTracks::value_type{ ptr->Duplicate().release() } );
for (auto it = dst.begin(), last = dst.end(); it != last; ++it)
(*it)->SetOwner(self, it);
};
copyLOT( *this, mSelf, that );
copyLOT( this->mPendingAdditions, mSelf, that.mPendingAdditions );
copyLOT( this->mPendingUpdates, mSelf, that.mPendingUpdates );
mUpdaters = that.mUpdaters;
TrackListConstIterator it(&that);
for (const Track *track = it.First(); track; track = it.Next())
Add(track->Duplicate());
}
void TrackList::Swap(TrackList &that)
{
auto SwapLOTs = [](
ListOfTracks &a, const std::weak_ptr< TrackList > &aSelf,
ListOfTracks &b, const std::weak_ptr< TrackList > &bSelf )
{
a.swap(b);
for (auto it = a.begin(), last = a.end(); it != last; ++it)
(*it)->SetOwner(aSelf, it);
for (auto it = b.begin(), last = b.end(); it != last; ++it)
(*it)->SetOwner(bSelf, it);
};
SwapLOTs( *this, mSelf, that, that.mSelf );
SwapLOTs( this->mPendingAdditions, mSelf, that.mPendingAdditions, that.mSelf );
SwapLOTs( this->mPendingUpdates, mSelf, that.mPendingUpdates, that.mSelf );
mUpdaters.swap(that.mUpdaters);
ListOfTracks::swap(that);
for (auto it = ListOfTracks::begin(), last = ListOfTracks::end();
it != last; ++it)
(*it)->SetOwner(this->mSelf, it);
for (auto it = that.ListOfTracks::begin(), last = that.ListOfTracks::end();
it != last; ++it)
(*it)->SetOwner(that.mSelf, it);
}
TrackList::~TrackList()
@@ -854,15 +780,16 @@ TrackList::~TrackList()
void TrackList::RecalcPositions(TrackNodePointer node)
{
if ( isNull( node ) )
if (isNull(node)) {
return;
}
Track *t;
int i = 0;
int y = 0;
auto prev = getPrev( node );
if ( !isNull( prev ) ) {
if (hasPrev(node)) {
auto prev = node;
--prev;
t = prev->get();
i = t->GetIndex() + 1;
y = t->GetY() + t->GetHeight();
@@ -872,11 +799,9 @@ void TrackList::RecalcPositions(TrackNodePointer node)
for (auto n = TrackListIterator{ this, node }; n != theEnd; ++n) {
t = *n;
t->SetIndex(i++);
t->DoSetY(y);
t->SetY(y);
y += t->GetHeight();
}
UpdatePendingTracks();
}
void TrackList::PermutationEvent()
@@ -909,32 +834,19 @@ void TrackList::Permute(const std::vector<TrackNodePointer> &permutation)
Track *pTrack = track.get();
pTrack->SetOwner(mSelf, insert(ListOfTracks::end(), std::move(track)));
}
auto n = getBegin();
auto n = ListOfTracks::begin();
RecalcPositions(n);
PermutationEvent();
}
Track *TrackList::FindById( TrackId id )
{
// Linear search. Tracks in a project are usually very few.
// Search only the non-pending tracks.
auto it = std::find_if( ListOfTracks::begin(), ListOfTracks::end(),
[=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
if (it == ListOfTracks::end())
return {};
return it->get();
}
template<typename TrackKind>
Track *TrackList::Add(std::unique_ptr<TrackKind> &&t)
{
Track *pTrack;
push_back(ListOfTracks::value_type(pTrack = t.release()));
auto n = getPrev( getEnd() );
auto n = ListOfTracks::end();
--n;
pTrack->SetOwner(mSelf, n);
pTrack->SetId( TrackId{ ++mCounter } );
RecalcPositions(n);
ResizingEvent(n);
return back().get();
@@ -954,9 +866,8 @@ Track *TrackList::AddToHead(std::unique_ptr<TrackKind> &&t)
{
Track *pTrack;
push_front(ListOfTracks::value_type(pTrack = t.release()));
auto n = getBegin();
auto n = ListOfTracks::begin();
pTrack->SetOwner(mSelf, n);
pTrack->SetId( TrackId{ ++mCounter } );
RecalcPositions(n);
ResizingEvent(n);
return front().get();
@@ -969,11 +880,9 @@ template<typename TrackKind>
Track *TrackList::Add(std::shared_ptr<TrackKind> &&t)
{
push_back(t);
auto n = getPrev( getEnd() );
auto n = ListOfTracks::end();
--n;
t->SetOwner(mSelf, n);
t->SetId( TrackId{ ++mCounter } );
RecalcPositions(n);
ResizingEvent(n);
return back().get();
@@ -996,7 +905,6 @@ auto TrackList::Replace(Track * t, ListOfTracks::value_type &&with) ->
Track *pTrack = with.get();
*node = std::move(with);
pTrack->SetOwner(mSelf, node);
pTrack->SetId( t->GetId() );
RecalcPositions(node);
DeletionEvent();
@@ -1007,18 +915,18 @@ auto TrackList::Replace(Track * t, ListOfTracks::value_type &&with) ->
TrackNodePointer TrackList::Remove(Track *t)
{
auto result = getEnd();
auto result = ListOfTracks::end();
if (t) {
auto node = t->GetNode();
t->SetOwner({}, {});
if ( !isNull( node ) ) {
if (!isNull(node)) {
ListOfTracks::value_type holder = std::move( *node );
result = getNext( node );
erase(node);
if ( !isNull( result ) )
result = erase(node);
if (!isNull(result)) {
RecalcPositions(result);
}
DeletionEvent();
}
@@ -1032,22 +940,9 @@ void TrackList::Clear(bool sendEvent)
// shared_ptrs to those tracks.
for ( auto pTrack: *this )
pTrack->SetOwner( {}, {} );
for ( auto pTrack: mPendingAdditions )
pTrack->SetOwner( {}, {} );
for ( auto pTrack: mPendingAdditions )
pTrack->SetOwner( {}, {} );
ListOfTracks tempList;
tempList.swap( *this );
ListOfTracks additional;
additional.swap( mPendingAdditions );
ListOfTracks updating;
updating.swap( mPendingAdditions );
mUpdaters.clear();
if (sendEvent)
DeletionEvent();
}
@@ -1056,17 +951,19 @@ void TrackList::Select(Track * t, bool selected /* = true */ )
{
if (t) {
const auto node = t->GetNode();
if ( !isNull( node ) ) {
t->SetSelected( selected );
if ( t->GetLinked() ) {
auto next = getNext( node );
if ( !isNull( next ) )
(*next)->SetSelected( selected );
if (!isNull(node)) {
t->SetSelected(selected);
auto next = node;
++next;
if (t->GetLinked() && !isNull(next)) {
(*next)->SetSelected(selected);
}
else {
auto prev = getPrev( node );
if ( !isNull( prev ) && (*prev)->GetLinked() )
(*prev)->SetSelected( selected );
else if (hasPrev(node)) {
auto prev = node;
--prev;
if ((*prev)->GetLinked()) {
(*prev)->SetSelected(selected);
}
}
}
}
@@ -1077,55 +974,50 @@ Track *TrackList::GetNext(Track * t, bool linked) const
{
if (t) {
auto node = t->GetNode();
if ( !isNull( node ) ) {
if ( linked && t->GetLinked() )
node = getNext( node );
if (!isNull(node)) {
if (linked && t->GetLinked()) {
++node;
}
if ( !isNull( node ) )
node = getNext( node );
if (!isNull(node)) {
++node;
}
if ( !isNull( node ) )
if (!isNull(node)) {
return node->get();
}
}
}
return nullptr;
return NULL;
}
Track *TrackList::GetPrev(Track * t, bool linked) const
{
if (t) {
TrackNodePointer prev;
auto node = t->GetNode();
if ( !isNull( node ) ) {
if (!isNull(node)) {
// linked is true and input track second in team?
if (linked) {
prev = getPrev( node );
if( !isNull( prev ) &&
!t->GetLinked() && t->GetLink() )
if (linked && hasPrev(node) &&
!t->GetLinked() && t->GetLink())
// Make it the first
node = prev;
}
--node;
prev = getPrev( node );
if ( !isNull( prev ) ) {
if (hasPrev(node)) {
// Back up once
node = prev;
--node;
// Back up twice sometimes when linked is true
if (linked) {
prev = getPrev( node );
if( !isNull( prev ) &&
!(*node)->GetLinked() && (*node)->GetLink() )
node = prev;
}
if (linked && hasPrev(node) &&
!(*node)->GetLinked() && (*node)->GetLink())
--node;
return node->get();
}
}
}
return nullptr;
return NULL;
}
/// For mono track height of track
@@ -1260,7 +1152,7 @@ size_t TrackList::size() const
int cnt = 0;
if (!empty())
cnt = getPrev( getEnd() )->get()->GetIndex() + 1;
cnt = back()->GetIndex() + 1;
return cnt;
}
@@ -1398,7 +1290,7 @@ int TrackList::GetHeight() const
int height = 0;
if (!empty()) {
auto track = getPrev( getEnd() )->get();
const auto &track = back();
height = track->GetY() + track->GetHeight();
}
@@ -1443,186 +1335,3 @@ double TrackList::GetEndTime() const
{
return Accumulate(*this, &Track::GetEndTime, doubleMax);
}
std::shared_ptr<Track>
TrackList::RegisterPendingChangedTrack( Updater updater, Track *src )
{
std::shared_ptr<Track> pTrack;
if (src)
// convert from unique_ptr to shared_ptr
pTrack.reset( src->Duplicate().release() );
if (pTrack) {
mUpdaters.push_back( updater );
mPendingUpdates.push_back( pTrack );
auto n = mPendingUpdates.end();
--n;
pTrack->SetOwner(mSelf, n);
}
return pTrack;
}
void TrackList::RegisterPendingNewTrack( const std::shared_ptr<Track> &pTrack )
{
pTrack->SetIndex( size() );
pTrack->SetY( GetHeight() );
mPendingAdditions.push_back(pTrack);
pTrack->SetOwner(mSelf, getPrev( getEnd() ));
}
void TrackList::UpdatePendingTracks()
{
auto pUpdater = mUpdaters.begin();
for (const auto &pendingTrack : mPendingUpdates) {
// Copy just a part of the track state, according to the update
// function
const auto &updater = *pUpdater;
auto src = FindById( pendingTrack->GetId() );
if (pendingTrack && src) {
if (updater)
updater( *pendingTrack, *src );
pendingTrack->DoSetY(src->GetY());
pendingTrack->DoSetHeight(src->GetHeight());
pendingTrack->DoSetMinimized(src->GetMinimized());
pendingTrack->DoSetLinked(src->GetLinked());
}
++pUpdater;
}
}
void TrackList::ClearPendingTracks()
// NOFAIL-GUARANTEE
{
for (const auto &pTrack: mPendingUpdates)
pTrack->SetOwner( {}, {} );
for (const auto &pTrack: mPendingAdditions)
pTrack->SetOwner( {}, {} );
mPendingAdditions.clear();
mPendingUpdates.clear();
mUpdaters.clear();
}
bool TrackList::ApplyPendingTracks()
{
bool result = false;
// Always clear, even if one of the update functions throws
auto cleanup = finally( [this] { ClearPendingTracks(); } );
UpdatePendingTracks();
// Remaining steps must be NOFAIL-GUARANTEE so that this function
// gives STRONG-GUARANTEE
std::vector< std::shared_ptr<Track> > reinstated;
ListOfTracks updates;
updates.swap( mPendingUpdates );
ListOfTracks additions;
additions.swap( mPendingAdditions );
for (auto &pendingTrack : updates) {
if (pendingTrack) {
auto src = FindById( pendingTrack->GetId() );
if (src)
this->Replace(src, std::move(pendingTrack)), result = true;
else
// Perhaps a track marked for pending changes got deleted by
// some other action. Recreate it so we don't lose the
// accumulated changes.
reinstated.push_back(pendingTrack);
}
}
// If there are tracks to reinstate, append them to the list before the
// additional tracks.
for (auto &pendingTrack : reinstated)
if (pendingTrack)
this->Add(std::move(pendingTrack)), result = true;
for (auto &pendingTrack : additions)
if (pendingTrack)
this->Add(std::move(pendingTrack)), result = true;
return result;
}
std::shared_ptr<Track> TrackList::FindPendingChangedTrack(TrackId id) const
{
// Linear search. Tracks in a project are usually very few.
auto it = std::find_if( mPendingUpdates.begin(), mPendingUpdates.end(),
[=](const ListOfTracks::value_type &ptr){ return ptr->GetId() == id; } );
if (it == mPendingUpdates.end())
return {};
return *it;
}
// Make begin iterator
PendingTrackIterator::PendingTrackIterator
(TrackList *list, const std::shared_ptr<TrackListIterator> &pIter)
: mList{ list }
, mpIter{ pIter }
{
auto &pending = mList->FindPendingNewTracks();
// Assume no invalidation of these iterators happens during the lifetime
// of this!
mpPendingIt = pending.begin(), mpPendingEnd = pending.end();
mpTrack = Track::Pointer( mpIter->First() );
SubstituteTrack();
mDoingExtras = !mpTrack;
FindExtraTrack();
}
// Make end iterator; the only important thing is to define operators == and
// != with other iterators
PendingTrackIterator::PendingTrackIterator()
: mList{ nullptr }
, mpIter{ }
{
mDoingExtras = true;
}
PendingTrackIterator &PendingTrackIterator::operator++()
{
if (!mDoingExtras) {
Track *next = mpIter->Next();
if (next) {
mpTrack = Track::Pointer( next );
SubstituteTrack();
}
else
mDoingExtras = true;
}
FindExtraTrack();
return *this;
}
void PendingTrackIterator::SubstituteTrack()
{
if (mpTrack) {
auto sub = mList->FindPendingChangedTrack( mpTrack->GetId() );
if (sub)
mpTrack = sub;
}
}
void PendingTrackIterator::FindExtraTrack()
{
if (mDoingExtras) {
auto pCondIter = dynamic_cast<TrackListCondIterator*>(mpIter.get());
while(
mpTrack.reset(),
mpPendingIt != mpPendingEnd &&
(mpTrack = *mpPendingIt++,
pCondIter &&
!pCondIter->Condition(mpTrack.get())))
{}
}
}