Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
TransactionalActionStack.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 using SiliconStudio.Core;
8 
9 namespace SiliconStudio.ActionStack
10 {
11  /// <summary>
12  /// This class is an implementation of the <see cref="ITransactionalActionStack"/> interface.
13  /// </summary>
14  /// <remarks>
15  /// A transactional action stack is an action stack that generates <see cref="IAggregateActionItem"/> from the action items that are added after a
16  /// transaction is started and before it is finished. A transaction can also be cancelled (undone) or discarded instead of creating an aggregate action item.
17  /// Multiple transactions can be created at the same time, each transaction that ends will become a single item of the parent transaction in progress.
18  /// </remarks>
20  {
21  /// <summary>
22  /// The stack of transactions currently in progress.
23  /// </summary>
24  protected readonly Stack<List<IActionItem>> TransactionStack = new Stack<List<IActionItem>>();
25 
26  /// <summary>
27  /// Initializes a new instance of the <see cref="TransactionalActionStack"/> class with the given capacity.
28  /// </summary>
29  /// <param name="capacity">The stack capacity. If negative, the action stack will have an unlimited capacity.</param>
30  public TransactionalActionStack(int capacity)
31  : base(capacity)
32  {
33  }
34 
35  /// <summary>
36  /// Initializes a new instance of the <see cref="TransactionalActionStack"/> class with the given capacity and existing action items.
37  /// </summary>
38  /// <param name="capacity">The stack capacity. If negative, the action stack will have an unlimited capacity.</param>
39  /// <param name="initialActionsItems">The action items to add to the stack.</param>
40  public TransactionalActionStack(int capacity, IEnumerable<IActionItem> initialActionsItems)
41  : base(capacity, initialActionsItems)
42  {
43  }
44 
45  /// <inheritdoc/>
46  public IDisposable BeginEndTransaction(string name)
47  {
48  BeginTransaction();
49  return new AnonymousDisposable(() => EndTransaction(name));
50  }
51 
52  /// <inheritdoc/>
53  public IDisposable BeginEndTransaction(Func<string> getName)
54  {
55  BeginTransaction();
56  return new AnonymousDisposable(() =>
57  {
58  string displayName;
59  try
60  {
61  displayName = getName();
62  }
63  catch
64  {
65  displayName = "<<ERROR>>";
66  }
67 
68  EndTransaction(displayName);
69  });
70  }
71 
72  /// <inheritdoc/>
73  public IDisposable BeginCancelTransaction()
74  {
75  BeginTransaction();
76  return new AnonymousDisposable(CancelTransaction);
77  }
78 
79  /// <inheritdoc/>
80  public IDisposable BeginDiscardTransaction()
81  {
82  BeginTransaction();
83  return new AnonymousDisposable(DiscardTransaction);
84  }
85 
86  /// <inheritdoc/>
87  public virtual void BeginTransaction()
88  {
89  var currentTransaction = new List<IActionItem>();
90  TransactionStack.Push(currentTransaction);
91  }
92 
93  /// <inheritdoc/>
94  public void EndTransaction(string name)
95  {
96  EndTransaction(name, x => AggregateActionItems(x, name));
97  }
98 
99  /// <inheritdoc/>
100  public virtual void EndTransaction(string name, Func<IReadOnlyCollection<IActionItem>, IActionItem> aggregateActionItems)
101  {
102  if (TransactionStack.Count == 0) throw new InvalidOperationException(Properties.ExceptionMessages.CannotEndNoTransactionInProgress);
103 
104  var currentTransaction = TransactionStack.Pop();
105  var aggregateActionItem = aggregateActionItems(currentTransaction);
106  Add(aggregateActionItem);
107  }
108 
109  /// <inheritdoc/>
110  public virtual void CancelTransaction()
111  {
112  if (TransactionStack.Count == 0) throw new InvalidOperationException(Properties.ExceptionMessages.CannotEndNoTransactionInProgress);
113  var currentTransaction = TransactionStack.Pop();
114  foreach (IActionItem item in currentTransaction.Reverse<IActionItem>())
115  {
116  item.Undo();
117  }
118  }
119 
120  /// <inheritdoc/>
121  public virtual void DiscardTransaction()
122  {
123  if (TransactionStack.Count == 0) throw new InvalidOperationException(Properties.ExceptionMessages.CannotEndNoTransactionInProgress);
124  TransactionStack.Pop();
125  }
126 
127  /// <summary>
128  /// Gets the action items in the current transaction.
129  /// </summary>
130  /// <returns>The action items in the current transaction.</returns>
131  public IReadOnlyCollection<IActionItem> GetCurrentTransactions()
132  {
133  if (TransactionStack.Count == 0) throw new InvalidOperationException(Properties.ExceptionMessages.NoTransactionInProgress);
134  return TransactionStack.Peek();
135  }
136 
137  /// <inheritdoc/>
138  public override void Add(IActionItem item)
139  {
140  if (!UndoRedoInProgress && TransactionStack.Count > 0)
141  {
142  var currentTransaction = TransactionStack.Peek();
143  currentTransaction.Add(item);
144  }
145  else
146  {
147  base.Add(item);
148  }
149  }
150 
151  private static IActionItem AggregateActionItems(IReadOnlyCollection<IActionItem> actionItems, string name = null)
152  {
153  if (actionItems.Count == 1)
154  {
155  var actionItem = actionItems.First();
156  if (!string.IsNullOrEmpty(name))
157  actionItem.Name = name;
158  return actionItem;
159  }
160  return new AggregateActionItem(name, actionItems);
161  }
162  }
163 }
override void Add(IActionItem item)
Adds an action item to the stack. Discards any action item that is currently undone. The action item to add to the stack.
This class is an implementation of the ITransactionalActionStack interface.
virtual void CancelTransaction()
Cancels a transaction started with BeginTransaction. Every action from the cancelled transaction will...
IDisposable BeginDiscardTransaction()
Creates a BeginTransaction-DiscardTransaction transaction subscription. Use it with a using statement...
virtual void DiscardTransaction()
Discard a transaction started with BeginTransaction. This method will ends the transaction and discar...
TransactionalActionStack(int capacity, IEnumerable< IActionItem > initialActionsItems)
Initializes a new instance of the TransactionalActionStack class with the given capacity and existing...
IDisposable BeginEndTransaction(Func< string > getName)
Creates a BeginTransaction-EndTransaction subscription. Use it with a using statement to ensure balan...
IReadOnlyCollection< IActionItem > GetCurrentTransactions()
Gets the action items in the current transaction.
void EndTransaction(string name)
Ends a transaction started with BeginTransaction. Once the transaction is ended, an aggregate action ...
IDisposable BeginEndTransaction(string name)
Creates a BeginTransaction-EndTransaction subscription. Use it with a using statement to ensure balan...
IDisposable BeginCancelTransaction()
Creates a BeginTransaction-CancelTransaction transaction subscription. Use it with a using statement ...
Base interface for action items.
Definition: IActionItem.cs:10
string Name
Gets or sets the name of the current action.
Definition: IActionItem.cs:15
virtual void EndTransaction(string name, Func< IReadOnlyCollection< IActionItem >, IActionItem > aggregateActionItems)
Ends a transaction started with BeginTransaction. A function that will aggregate an enumeration of ac...
This class allows implementation of IDisposable using anonymous functions. The anonymous function wil...
TransactionalActionStack(int capacity)
Initializes a new instance of the TransactionalActionStack class with the given capacity.
Item discarded because an undo/redo operation is currently in progress.
This class represents a thread-safe stack of action items that can be undone/redone.
Definition: ActionStack.cs:12
virtual void BeginTransaction()
Begins a transaction. IActionItem added after a call to BeginTransaction are stored in a temporary tr...
Base interface for a transactional action stack.