1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-14 11:37:52 +08:00
osu-lazer/osu.Game/Screens/Edit/TransactionalCommitComponent.cs

76 lines
2.4 KiB
C#
Raw Normal View History

// 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 15:37:17 +08:00
#nullable disable
using System;
2020-10-08 16:17:52 +08:00
using osu.Framework.Graphics;
namespace osu.Game.Screens.Edit
{
/// <summary>
/// A component that tracks a batch change, only applying after all active changes are completed.
/// </summary>
2022-11-24 13:32:20 +08:00
public abstract partial class TransactionalCommitComponent : Component
{
2020-10-08 16:17:52 +08: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;
public bool TransactionActive => bulkChangesStarted > 0;
private int bulkChangesStarted;
/// <summary>
/// Signal the beginning of a change.
/// </summary>
2020-10-08 16:17:52 +08:00
public void BeginChange()
{
if (bulkChangesStarted++ == 0)
TransactionBegan?.Invoke();
}
/// <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 16:17:52 +08:00
{
UpdateState();
2020-10-08 16:17:52 +08:00
TransactionEnded?.Invoke();
}
}
2020-10-08 16:17:52 +08: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>
public void SaveState()
{
if (bulkChangesStarted > 0)
return;
2020-10-08 16:17:52 +08:00
SaveStateTriggered?.Invoke();
UpdateState();
}
protected abstract void UpdateState();
}
}