OpenShot Library | OpenShotAudio  0.2.2
juce_UndoManager.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
31 {
32  ActionSet (const String& transactionName) : name (transactionName)
33  {}
34 
35  bool perform() const
36  {
37  for (auto* a : actions)
38  if (! a->perform())
39  return false;
40 
41  return true;
42  }
43 
44  bool undo() const
45  {
46  for (int i = actions.size(); --i >= 0;)
47  if (! actions.getUnchecked(i)->undo())
48  return false;
49 
50  return true;
51  }
52 
53  int getTotalSize() const
54  {
55  int total = 0;
56 
57  for (auto* a : actions)
58  total += a->getSizeInUnits();
59 
60  return total;
61  }
62 
64  String name;
65  Time time { Time::getCurrentTime() };
66 };
67 
68 //==============================================================================
69 UndoManager::UndoManager (int maxNumberOfUnitsToKeep, int minimumTransactions)
70 {
71  setMaxNumberOfStoredUnits (maxNumberOfUnitsToKeep, minimumTransactions);
72 }
73 
75 {
76 }
77 
78 //==============================================================================
80 {
81  transactions.clear();
82  totalUnitsStored = 0;
83  nextIndex = 0;
85 }
86 
88 {
89  return totalUnitsStored;
90 }
91 
92 void UndoManager::setMaxNumberOfStoredUnits (int maxUnits, int minTransactions)
93 {
94  maxNumUnitsToKeep = jmax (1, maxUnits);
95  minimumTransactionsToKeep = jmax (1, minTransactions);
96 }
97 
98 //==============================================================================
99 bool UndoManager::perform (UndoableAction* newAction, const String& actionName)
100 {
101  if (perform (newAction))
102  {
103  if (actionName.isNotEmpty())
104  setCurrentTransactionName (actionName);
105 
106  return true;
107  }
108 
109  return false;
110 }
111 
113 {
114  if (newAction != nullptr)
115  {
116  std::unique_ptr<UndoableAction> action (newAction);
117 
118  if (isPerformingUndoRedo())
119  {
120  jassertfalse; // Don't call perform() recursively from the UndoableAction::perform()
121  // or undo() methods, or else these actions will be discarded!
122  return false;
123  }
124 
125  if (action->perform())
126  {
127  auto* actionSet = getCurrentSet();
128 
129  if (actionSet != nullptr && ! newTransaction)
130  {
131  if (auto* lastAction = actionSet->actions.getLast())
132  {
133  if (auto coalescedAction = lastAction->createCoalescedAction (action.get()))
134  {
135  action.reset (coalescedAction);
136  totalUnitsStored -= lastAction->getSizeInUnits();
137  actionSet->actions.removeLast();
138  }
139  }
140  }
141  else
142  {
143  actionSet = new ActionSet (newTransactionName);
144  transactions.insert (nextIndex, actionSet);
145  ++nextIndex;
146  }
147 
148  totalUnitsStored += action->getSizeInUnits();
149  actionSet->actions.add (std::move (action));
150  newTransaction = false;
151 
152  moveFutureTransactionsToStash();
153  dropOldTransactionsIfTooLarge();
155  return true;
156  }
157  }
158 
159  return false;
160 }
161 
162 void UndoManager::moveFutureTransactionsToStash()
163 {
164  if (nextIndex < transactions.size())
165  {
166  stashedFutureTransactions.clear();
167 
168  while (nextIndex < transactions.size())
169  {
170  auto* removed = transactions.removeAndReturn (nextIndex);
171  stashedFutureTransactions.add (removed);
172  totalUnitsStored -= removed->getTotalSize();
173  }
174  }
175 }
176 
177 void UndoManager::restoreStashedFutureTransactions()
178 {
179  while (nextIndex < transactions.size())
180  {
181  totalUnitsStored -= transactions.getUnchecked (nextIndex)->getTotalSize();
182  transactions.remove (nextIndex);
183  }
184 
185  for (auto* stashed : stashedFutureTransactions)
186  {
187  transactions.add (stashed);
188  totalUnitsStored += stashed->getTotalSize();
189  }
190 
191  stashedFutureTransactions.clearQuick (false);
192 }
193 
194 void UndoManager::dropOldTransactionsIfTooLarge()
195 {
196  while (nextIndex > 0
197  && totalUnitsStored > maxNumUnitsToKeep
198  && transactions.size() > minimumTransactionsToKeep)
199  {
200  totalUnitsStored -= transactions.getFirst()->getTotalSize();
201  transactions.remove (0);
202  --nextIndex;
203 
204  // if this fails, then some actions may not be returning
205  // consistent results from their getSizeInUnits() method
206  jassert (totalUnitsStored >= 0);
207  }
208 }
209 
211 {
212  beginNewTransaction ({});
213 }
214 
215 void UndoManager::beginNewTransaction (const String& actionName)
216 {
217  newTransaction = true;
218  newTransactionName = actionName;
219 }
220 
222 {
223  if (newTransaction)
224  newTransactionName = newName;
225  else if (auto* action = getCurrentSet())
226  action->name = newName;
227 }
228 
230 {
231  if (auto* action = getCurrentSet())
232  return action->name;
233 
234  return newTransactionName;
235 }
236 
237 //==============================================================================
238 UndoManager::ActionSet* UndoManager::getCurrentSet() const { return transactions[nextIndex - 1]; }
239 UndoManager::ActionSet* UndoManager::getNextSet() const { return transactions[nextIndex]; }
240 
241 bool UndoManager::isPerformingUndoRedo() const { return isInsideUndoRedoCall; }
242 
243 bool UndoManager::canUndo() const { return getCurrentSet() != nullptr; }
244 bool UndoManager::canRedo() const { return getNextSet() != nullptr; }
245 
247 {
248  if (auto* s = getCurrentSet())
249  {
250  const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
251 
252  if (s->undo())
253  --nextIndex;
254  else
256 
259  return true;
260  }
261 
262  return false;
263 }
264 
266 {
267  if (auto* s = getNextSet())
268  {
269  const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
270 
271  if (s->perform())
272  ++nextIndex;
273  else
275 
278  return true;
279  }
280 
281  return false;
282 }
283 
285 {
286  if (auto* s = getCurrentSet())
287  return s->name;
288 
289  return {};
290 }
291 
293 {
294  if (auto* s = getNextSet())
295  return s->name;
296 
297  return {};
298 }
299 
301 {
302  StringArray descriptions;
303 
304  for (int i = nextIndex;;)
305  {
306  if (auto* t = transactions[--i])
307  descriptions.add (t->name);
308  else
309  return descriptions;
310  }
311 }
312 
314 {
315  StringArray descriptions;
316 
317  for (int i = nextIndex;;)
318  {
319  if (auto* t = transactions[i++])
320  descriptions.add (t->name);
321  else
322  return descriptions;
323  }
324 }
325 
327 {
328  if (auto* s = getCurrentSet())
329  return s->time;
330 
331  return {};
332 }
333 
335 {
336  if (auto* s = getNextSet())
337  return s->time;
338 
339  return Time::getCurrentTime();
340 }
341 
343 {
344  if ((! newTransaction) && undo())
345  {
346  restoreStashedFutureTransactions();
347  return true;
348  }
349 
350  return false;
351 }
352 
354 {
355  if (! newTransaction)
356  if (auto* s = getCurrentSet())
357  for (auto* a : s->actions)
358  actionsFound.add (a);
359 }
360 
362 {
363  if (! newTransaction)
364  if (auto* s = getCurrentSet())
365  return s->actions.size();
366 
367  return 0;
368 }
369 
370 } // namespace juce
String getUndoDescription() const
Returns the name of the transaction that will be rolled-back when undo() is called.
bool undoCurrentTransactionOnly()
Tries to roll-back any actions that were added to the current transaction.
bool undo()
Tries to roll-back the last transaction.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Definition: juce_String.h:306
StringArray getUndoDescriptions() const
Returns the names of the sequence of transactions that will be performed if undo() is repeatedly call...
Time getTimeOfUndoTransaction() const
Returns the time to which the state would be restored if undo() was to be called. ...
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:422
void beginNewTransaction()
Starts a new group of actions that together will be treated as a single transaction.
bool canRedo() const
Returns true if there&#39;s at least one action in the list to redo.
bool redo()
Tries to redo the last transaction that was undone.
int getNumberOfUnitsTakenUpByStoredCommands() const
Returns the current amount of space to use for storing UndoableAction objects.
A special array for holding a list of strings.
The JUCE String class!
Definition: juce_String.h:42
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
Definition: juce_Time.cpp:218
void setCurrentTransactionName(const String &newName)
Changes the name stored for the current transaction.
~UndoManager() override
Destructor.
bool isPerformingUndoRedo() const
Returns true if the caller code is in the middle of an undo or redo action.
Time getTimeOfRedoTransaction() const
Returns the time to which the state would be restored if redo() was to be called. ...
Helper class providing an RAII-based mechanism for temporarily setting and then re-setting a value...
bool canUndo() const
Returns true if there&#39;s at least one action in the list to undo.
void clearUndoHistory()
Deletes all stored actions in the list.
bool perform(UndoableAction *action)
Performs an action and adds it to the undo history list.
void setMaxNumberOfStoredUnits(int maxNumberOfUnitsToKeep, int minimumTransactionsToKeep)
Sets the amount of space that can be used for storing UndoableAction objects.
Holds a resizable array of primitive or copy-by-value objects.
Definition: juce_Array.h:59
void sendChangeMessage()
Causes an asynchronous change message to be sent to all the registered listeners. ...
StringArray getRedoDescriptions() const
Returns the names of the sequence of transactions that will be performed if redo() is repeatedly call...
Used by the UndoManager class to store an action which can be done and undone.
int getNumActionsInCurrentTransaction() const
Returns the number of UndoableAction objects that have been performed during the transaction that is ...
String getCurrentTransactionName() const
Returns the name of the current transaction.
String getRedoDescription() const
Returns the name of the transaction that will be redone when redo() is called.
An array designed for holding objects.
void getActionsInCurrentTransaction(Array< const UndoableAction *> &actionsFound) const
Returns a list of the UndoableAction objects that have been performed during the transaction that is ...
Holds an absolute date and time.
Definition: juce_Time.h:40
UndoManager(int maxNumberOfUnitsToKeep=30000, int minimumTransactionsToKeep=30)
Creates an UndoManager.
void add(String stringToAdd)
Appends a string at the end of the array.