OpenShot Library | libopenshot-audio  0.2.0
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 (action.release());
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
juce::StringArray
A special array for holding a list of strings.
Definition: juce_StringArray.h:38
juce::UndoManager::getRedoDescription
String getRedoDescription() const
Returns the name of the transaction that will be redone when redo() is called.
Definition: juce_UndoManager.cpp:292
juce::UndoManager::getRedoDescriptions
StringArray getRedoDescriptions() const
Returns the names of the sequence of transactions that will be performed if redo() is repeatedly call...
Definition: juce_UndoManager.cpp:313
juce::UndoManager::beginNewTransaction
void beginNewTransaction()
Starts a new group of actions that together will be treated as a single transaction.
Definition: juce_UndoManager.cpp:210
juce::UndoManager::ActionSet
Definition: juce_UndoManager.cpp:30
juce::UndoableAction
Used by the UndoManager class to store an action which can be done and undone.
Definition: juce_UndoableAction.h:43
juce::UndoManager::clearUndoHistory
void clearUndoHistory()
Deletes all stored actions in the list.
Definition: juce_UndoManager.cpp:79
juce::UndoManager::UndoManager
UndoManager(int maxNumberOfUnitsToKeep=30000, int minimumTransactionsToKeep=30)
Creates an UndoManager.
Definition: juce_UndoManager.cpp:69
juce::UndoManager::canRedo
bool canRedo() const
Returns true if there's at least one action in the list to redo.
Definition: juce_UndoManager.cpp:244
juce::UndoManager::setCurrentTransactionName
void setCurrentTransactionName(const String &newName)
Changes the name stored for the current transaction.
Definition: juce_UndoManager.cpp:221
juce::OwnedArray
An array designed for holding objects.
Definition: juce_OwnedArray.h:54
juce::UndoManager::~UndoManager
~UndoManager() override
Destructor.
Definition: juce_UndoManager.cpp:74
juce::UndoManager::getActionsInCurrentTransaction
void getActionsInCurrentTransaction(Array< const UndoableAction * > &actionsFound) const
Returns a list of the UndoableAction objects that have been performed during the transaction that is ...
Definition: juce_UndoManager.cpp:353
juce::Array::add
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:375
juce::UndoManager::getTimeOfRedoTransaction
Time getTimeOfRedoTransaction() const
Returns the time to which the state would be restored if redo() was to be called.
Definition: juce_UndoManager.cpp:334
juce::UndoManager::canUndo
bool canUndo() const
Returns true if there's at least one action in the list to undo.
Definition: juce_UndoManager.cpp:243
juce::UndoManager::setMaxNumberOfStoredUnits
void setMaxNumberOfStoredUnits(int maxNumberOfUnitsToKeep, int minimumTransactionsToKeep)
Sets the amount of space that can be used for storing UndoableAction objects.
Definition: juce_UndoManager.cpp:92
juce::Array
Holds a resizable array of primitive or copy-by-value objects.
Definition: juce_Array.h:59
juce::UndoManager::redo
bool redo()
Tries to redo the last transaction that was undone.
Definition: juce_UndoManager.cpp:265
juce::Time::getCurrentTime
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
Definition: juce_Time.cpp:218
juce::UndoManager::getUndoDescriptions
StringArray getUndoDescriptions() const
Returns the names of the sequence of transactions that will be performed if undo() is repeatedly call...
Definition: juce_UndoManager.cpp:300
juce::ScopedValueSetter
Helper class providing an RAII-based mechanism for temporarily setting and then re-setting a value.
Definition: juce_ScopedValueSetter.h:58
juce::UndoManager::getCurrentTransactionName
String getCurrentTransactionName() const
Returns the name of the current transaction.
Definition: juce_UndoManager.cpp:229
juce::ChangeBroadcaster::sendChangeMessage
void sendChangeMessage()
Causes an asynchronous change message to be sent to all the registered listeners.
Definition: juce_ChangeBroadcaster.cpp:62
juce::Time
Holds an absolute date and time.
Definition: juce_Time.h:40
juce::UndoManager::getNumberOfUnitsTakenUpByStoredCommands
int getNumberOfUnitsTakenUpByStoredCommands() const
Returns the current amount of space to use for storing UndoableAction objects.
Definition: juce_UndoManager.cpp:87
juce::UndoManager::undoCurrentTransactionOnly
bool undoCurrentTransactionOnly()
Tries to roll-back any actions that were added to the current transaction.
Definition: juce_UndoManager.cpp:342
juce::UndoManager::getNumActionsInCurrentTransaction
int getNumActionsInCurrentTransaction() const
Returns the number of UndoableAction objects that have been performed during the transaction that is ...
Definition: juce_UndoManager.cpp:361
juce::UndoManager::undo
bool undo()
Tries to roll-back the last transaction.
Definition: juce_UndoManager.cpp:246
juce::UndoManager::isPerformingUndoRedo
bool isPerformingUndoRedo() const
Returns true if the caller code is in the middle of an undo or redo action.
Definition: juce_UndoManager.cpp:241
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Definition: juce_String.h:306
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::UndoManager::perform
bool perform(UndoableAction *action)
Performs an action and adds it to the undo history list.
Definition: juce_UndoManager.cpp:112
juce::StringArray::add
void add(String stringToAdd)
Appends a string at the end of the array.
Definition: juce_StringArray.cpp:135
juce::UndoManager::getUndoDescription
String getUndoDescription() const
Returns the name of the transaction that will be rolled-back when undo() is called.
Definition: juce_UndoManager.cpp:284
juce::UndoManager::getTimeOfUndoTransaction
Time getTimeOfUndoTransaction() const
Returns the time to which the state would be restored if undo() was to be called.
Definition: juce_UndoManager.cpp:326