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
27namespace juce
28{
29
31{
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//==============================================================================
73
77
78//==============================================================================
80{
81 transactions.clear();
82 totalUnitsStored = 0;
83 nextIndex = 0;
85}
86
88{
89 return totalUnitsStored;
90}
91
93{
94 maxNumUnitsToKeep = jmax (1, maxUnits);
95 minimumTransactionsToKeep = jmax (1, minTransactions);
96}
97
98//==============================================================================
100{
101 if (perform (newAction))
102 {
103 if (actionName.isNotEmpty())
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
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
162void 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
177void 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
194void 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
214
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//==============================================================================
238UndoManager::ActionSet* UndoManager::getCurrentSet() const { return transactions[nextIndex - 1]; }
239UndoManager::ActionSet* UndoManager::getNextSet() const { return transactions[nextIndex]; }
240
241bool UndoManager::isPerformingUndoRedo() const { return isInsideUndoRedoCall; }
242
243bool UndoManager::canUndo() const { return getCurrentSet() != nullptr; }
244bool 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{
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{
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)
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
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:60
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
Definition juce_Array.h:256
void removeLast(int howManyToRemove=1)
Removes the last n elements from the array.
Definition juce_Array.h:893
void clearQuick()
Removes all elements from the array without freeing the array's allocated storage.
Definition juce_Array.h:202
int size() const noexcept
Returns the current number of elements in the array.
Definition juce_Array.h:219
void remove(int indexToRemove)
Removes an element from the array.
Definition juce_Array.h:724
void insert(int indexToInsertAt, ParameterType newElement)
Inserts a new element into the array at a given position.
Definition juce_Array.h:419
ElementType getFirst() const noexcept
Returns the first element in the array, or a default value if the array is empty.
Definition juce_Array.h:280
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition juce_Array.h:375
ElementType removeAndReturn(int indexToRemove)
Removes an element from the array.
Definition juce_Array.h:742
void clear()
Removes all elements from the array.
Definition juce_Array.h:192
ElementType getLast() const noexcept
Returns the last element in the array, or a default value if the array is empty.
Definition juce_Array.h:290
void sendChangeMessage()
Causes an asynchronous change message to be sent to all the registered listeners.
A special array for holding a list of strings.
The JUCE String class!
Definition juce_String.h:43
Holds an absolute date and time.
Definition juce_Time.h:41
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
void beginNewTransaction()
Starts a new group of actions that together will be treated as a single transaction.
Time getTimeOfUndoTransaction() const
Returns the time to which the state would be restored if undo() was to be called.
String getCurrentTransactionName() const
Returns the name of the current transaction.
void setMaxNumberOfStoredUnits(int maxNumberOfUnitsToKeep, int minimumTransactionsToKeep)
Sets the amount of space that can be used for storing UndoableAction objects.
bool redo()
Tries to redo the last transaction that was undone.
String getRedoDescription() const
Returns the name of the transaction that will be redone when redo() is called.
StringArray getRedoDescriptions() const
Returns the names of the sequence of transactions that will be performed if redo() is repeatedly call...
bool undo()
Tries to roll-back the last transaction.
~UndoManager() override
Destructor.
bool isPerformingUndoRedo() const
Returns true if the caller code is in the middle of an undo or redo action.
void clearUndoHistory()
Deletes all stored actions in the list.
bool canUndo() const
Returns true if there's at least one action in the list to undo.
bool undoCurrentTransactionOnly()
Tries to roll-back any actions that were added to the current transaction.
int getNumberOfUnitsTakenUpByStoredCommands() const
Returns the current amount of space to use for storing UndoableAction objects.
bool perform(UndoableAction *action)
Performs an action and adds it to the undo history list.
Time getTimeOfRedoTransaction() const
Returns the time to which the state would be restored if redo() was to be called.
bool canRedo() const
Returns true if there's at least one action in the list to redo.
StringArray getUndoDescriptions() const
Returns the names of the sequence of transactions that will be performed if undo() is repeatedly call...
String getUndoDescription() const
Returns the name of the transaction that will be rolled-back when undo() is called.
UndoManager(int maxNumberOfUnitsToKeep=30000, int minimumTransactionsToKeep=30)
Creates an UndoManager.
void getActionsInCurrentTransaction(Array< const UndoableAction * > &actionsFound) const
Returns a list of the UndoableAction objects that have been performed during the transaction that is ...
int getNumActionsInCurrentTransaction() const
Returns the number of UndoableAction objects that have been performed during the transaction that is ...
void setCurrentTransactionName(const String &newName)
Changes the name stored for the current transaction.
Used by the UndoManager class to store an action which can be done and undone.