2020-10-08 07:57:04 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2022-06-17 07:37:17 +00:00
#nullable disable
2020-10-08 07:57:04 +00:00
using System ;
2020-10-08 08:17:52 +00:00
using osu.Framework.Graphics ;
2020-10-08 07:57:04 +00:00
namespace osu.Game.Screens.Edit
{
/// <summary>
/// A component that tracks a batch change, only applying after all active changes are completed.
/// </summary>
2020-10-08 08:17:52 +00:00
public abstract class TransactionalCommitComponent : Component
2020-10-08 07:57:04 +00:00
{
2020-10-08 08:17:52 +00:00
/// <summary>
/// Fires whenever a transaction begins. Will not fire on nested transactions.
/// </summary>
public event Action TransactionBegan ;
/// <summary>
/// Fires when the last transaction completes.
/// </summary>
public event Action TransactionEnded ;
/// <summary>
/// Fires when <see cref="SaveState"/> is called and results in a non-transactional state save.
/// </summary>
public event Action SaveStateTriggered ;
2020-10-08 07:57:04 +00:00
public bool TransactionActive = > bulkChangesStarted > 0 ;
private int bulkChangesStarted ;
/// <summary>
/// Signal the beginning of a change.
/// </summary>
2020-10-08 08:17:52 +00:00
public void BeginChange ( )
{
if ( bulkChangesStarted + + = = 0 )
TransactionBegan ? . Invoke ( ) ;
}
2020-10-08 07:57:04 +00:00
/// <summary>
/// Signal the end of a change.
/// </summary>
/// <exception cref="InvalidOperationException">Throws if <see cref="BeginChange"/> was not first called.</exception>
public void EndChange ( )
{
if ( bulkChangesStarted = = 0 )
throw new InvalidOperationException ( $"Cannot call {nameof(EndChange)} without a previous call to {nameof(BeginChange)}." ) ;
if ( - - bulkChangesStarted = = 0 )
2020-10-08 08:17:52 +00:00
{
2020-10-08 07:57:04 +00:00
UpdateState ( ) ;
2020-10-08 08:17:52 +00:00
TransactionEnded ? . Invoke ( ) ;
}
2020-10-08 07:57:04 +00:00
}
2020-10-08 08:17:52 +00:00
/// <summary>
/// Force an update of the state with no attached transaction.
/// This is a no-op if a transaction is already active. Should generally be used as a safety measure to ensure granular changes are not left outside a transaction.
/// </summary>
2020-10-08 07:57:04 +00:00
public void SaveState ( )
{
if ( bulkChangesStarted > 0 )
return ;
2020-10-08 08:17:52 +00:00
SaveStateTriggered ? . Invoke ( ) ;
2020-10-08 07:57:04 +00:00
UpdateState ( ) ;
}
protected abstract void UpdateState ( ) ;
}
}