OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
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
30struct UndoManager::ActionSet
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
63 OwnedArray<UndoableAction> actions;
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 (std::move (action));
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
void removeLast(int howManyToRemove=1)
Definition juce_Array.h:936
int size() const noexcept
Definition juce_Array.h:215
void add(const ElementType &newElement)
Definition juce_Array.h:418
ElementType getLast() const noexcept
Definition juce_Array.h:300
int size() const noexcept
ObjectClass * getUnchecked(int index) const noexcept
ObjectClass * removeAndReturn(int indexToRemove)
void remove(int indexToRemove, bool deleteObject=true)
ObjectClass * getFirst() const noexcept
void clear(bool deleteObjects=true)
ObjectClass * add(ObjectClass *newObject)
void clearQuick(bool deleteObjects)
ObjectClass * insert(int indexToInsertAt, ObjectClass *newObject)
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Time getTimeOfUndoTransaction() const
String getCurrentTransactionName() const
void setMaxNumberOfStoredUnits(int maxNumberOfUnitsToKeep, int minimumTransactionsToKeep)
String getRedoDescription() const
StringArray getRedoDescriptions() const
bool isPerformingUndoRedo() const
int getNumberOfUnitsTakenUpByStoredCommands() const
bool perform(UndoableAction *action)
Time getTimeOfRedoTransaction() const
StringArray getUndoDescriptions() const
String getUndoDescription() const
UndoManager(int maxNumberOfUnitsToKeep=30000, int minimumTransactionsToKeep=30)
void getActionsInCurrentTransaction(Array< const UndoableAction * > &actionsFound) const
int getNumActionsInCurrentTransaction() const
void setCurrentTransactionName(const String &newName)