|
1 /* |
|
2 * Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "UndoSystemImpl.h" |
|
20 #include "AssertFileAndLine.h" |
|
21 |
|
22 using namespace UndoSystem; |
|
23 |
|
24 namespace UndoSystemImpl |
|
25 { |
|
26 const TInt KCommandStackGranularity = 10; |
|
27 _LIT(KUndoPanic, "Undo System"); |
|
28 } |
|
29 |
|
30 using namespace UndoSystemImpl; |
|
31 |
|
32 |
|
33 void UndoSystem::Panic(TPanicCode aCode) |
|
34 { |
|
35 User::Panic(KUndoPanic, aCode); |
|
36 } |
|
37 |
|
38 ///////////////////// |
|
39 // // |
|
40 // CCommandStack // |
|
41 // // |
|
42 ///////////////////// |
|
43 |
|
44 CCommandStack::CCommandStack() : iEnd(0), iBookmark(0) {} |
|
45 |
|
46 CCommandStack::~CCommandStack() |
|
47 { |
|
48 if (iStack) |
|
49 { |
|
50 Reset(); |
|
51 delete iStack; |
|
52 } |
|
53 } |
|
54 |
|
55 void CCommandStack::ConstructL() |
|
56 { |
|
57 iStack = new(ELeave) CArrayFixSeg<CCommand*>(KCommandStackGranularity); |
|
58 } |
|
59 |
|
60 CCommandStack* CCommandStack::NewL() |
|
61 { |
|
62 CCommandStack* r = new(ELeave) CCommandStack(); |
|
63 CleanupStack::PushL(r); |
|
64 r->ConstructL(); |
|
65 CleanupStack::Pop(r); |
|
66 return r; |
|
67 } |
|
68 |
|
69 TInt CCommandStack::Count() const |
|
70 { |
|
71 ASSERT(iEnd <= iStack->Count()); |
|
72 return iEnd; |
|
73 } |
|
74 |
|
75 void CCommandStack::Reset() |
|
76 { |
|
77 PruneTo(0); |
|
78 iBookmark = -1; |
|
79 } |
|
80 |
|
81 CCommand* CCommandStack::Top() const |
|
82 { |
|
83 ASSERT(0 <= iEnd); |
|
84 ASSERT(iEnd <= iStack->Count()); |
|
85 return iEnd == 0? 0 : iStack->At(iEnd - 1); |
|
86 } |
|
87 |
|
88 CCommand* CCommandStack::Pop() |
|
89 { |
|
90 ASSERT(iEnd <= iStack->Count()); |
|
91 CCommand* top = Top(); |
|
92 __ASSERT_ALWAYS(top, UndoSystem::Panic(KCommandStackUnderflow)); |
|
93 TInt numSlots = iStack->Count() - iEnd + 1; |
|
94 ASSERT(numSlots <= iStack->Count()); |
|
95 iStack->Delete(iStack->Count() - numSlots, numSlots); |
|
96 iEnd = iStack->Count(); |
|
97 if (iEnd < iBookmark) |
|
98 iBookmark = -1; |
|
99 return top; |
|
100 } |
|
101 |
|
102 void CCommandStack::PruneTo(TInt aNumberOfItems) |
|
103 { |
|
104 ASSERT(iEnd <= iStack->Count()); |
|
105 iStack->Delete(iEnd, iStack->Count() - iEnd); |
|
106 iEnd = iStack->Count(); |
|
107 if (aNumberOfItems < iEnd) |
|
108 { |
|
109 TInt numberToDestroy = iEnd - aNumberOfItems; |
|
110 for (TInt i = 0; i != numberToDestroy; ++i) |
|
111 { |
|
112 delete iStack->At(i); |
|
113 } |
|
114 iStack->Delete(0, numberToDestroy); |
|
115 iStack->Compress(); |
|
116 iEnd = aNumberOfItems; |
|
117 iBookmark -= aNumberOfItems; |
|
118 } |
|
119 } |
|
120 |
|
121 void CCommandStack::PrepareToPushL(TInt aNumberOfItems) |
|
122 { |
|
123 iStack->ResizeL(iEnd + aNumberOfItems); |
|
124 } |
|
125 |
|
126 void CCommandStack::Push(CCommand* aCommand) |
|
127 { |
|
128 ASSERT(aCommand); |
|
129 __ASSERT_ALWAYS(iEnd < iStack->Count(), UndoSystem::Panic(KCommandStackPushNotPrepared)); |
|
130 iStack->At(iEnd) = aCommand; |
|
131 ++iEnd; |
|
132 } |
|
133 |
|
134 void CCommandStack::Concatenate(CCommandStack& aStack) |
|
135 { |
|
136 TInt thisCount = iEnd; |
|
137 iEnd += aStack.iEnd; |
|
138 __ASSERT_DEBUG(iEnd <= iStack->Count(), |
|
139 UndoSystem::Panic(KCommandStackPushNotPrepared)); |
|
140 for (TInt i = 0; i != aStack.iEnd; ++i, ++thisCount) |
|
141 iStack->At(thisCount) = (aStack.iStack->At(i)); |
|
142 aStack.iEnd = 0; |
|
143 aStack.iStack->Reset(); |
|
144 } |
|
145 |
|
146 void CCommandStack::SetBookmark() |
|
147 { |
|
148 iBookmark = iEnd; |
|
149 } |
|
150 |
|
151 TBool CCommandStack::IsAtBookmark() const |
|
152 { |
|
153 return iBookmark == iEnd? ETrue : EFalse; |
|
154 } |
|
155 |
|
156 CSingleCommandStack* CSingleCommandStack::NewL() |
|
157 { |
|
158 CSingleCommandStack* r = new(ELeave) CSingleCommandStack; |
|
159 CleanupStack::PushL(r); |
|
160 r->iStack.ConstructL(); |
|
161 CleanupStack::Pop(r); |
|
162 return r; |
|
163 } |
|
164 |
|
165 /////////////////////// |
|
166 // // |
|
167 // CCommandHistory // |
|
168 // // |
|
169 /////////////////////// |
|
170 |
|
171 CCommandHistory::CCommandHistory() |
|
172 : iMaxItems(KMaxTInt >> 1) |
|
173 { |
|
174 } |
|
175 |
|
176 CCommandHistory::~CCommandHistory() |
|
177 { |
|
178 delete iStack; |
|
179 } |
|
180 |
|
181 void CCommandHistory::ConstructL() |
|
182 { |
|
183 iStack = CCommandStack::NewL(); |
|
184 iCurrent = 0; |
|
185 } |
|
186 |
|
187 CCommandHistory* CCommandHistory::NewL() |
|
188 { |
|
189 CCommandHistory* r = new(ELeave) CCommandHistory(); |
|
190 CleanupStack::PushL(r); |
|
191 r->ConstructL(); |
|
192 CleanupStack::Pop(r); |
|
193 return r; |
|
194 } |
|
195 |
|
196 void CCommandHistory::Prune() |
|
197 { |
|
198 if (iMaxItems < iStack->Count()) |
|
199 iStack->PruneTo(iMaxItems); |
|
200 } |
|
201 |
|
202 void CCommandHistory::SetMaxItems(TInt aMaxItems) |
|
203 { |
|
204 ASSERT(0 < aMaxItems); |
|
205 iMaxItems = aMaxItems; |
|
206 Prune(); |
|
207 } |
|
208 |
|
209 void CCommandHistory::CloseBatch(void* a) |
|
210 { |
|
211 CCommandHistory* aThat = reinterpret_cast<CCommandHistory*>(a); |
|
212 aThat->iCurrent = 0; |
|
213 if (aThat->iBatchUndoHasBeenWaived) |
|
214 aThat->Reset(); |
|
215 } |
|
216 |
|
217 void CCommandHistory::DownBatchLevel(void*) {} |
|
218 |
|
219 TBool CCommandHistory::IsWithinBatch() const |
|
220 { |
|
221 return iCurrent? ETrue : EFalse; |
|
222 } |
|
223 |
|
224 void CCommandHistory::BeginBatchLC() |
|
225 { |
|
226 if (iCurrent) |
|
227 { |
|
228 CleanupStack::PushL(TCleanupItem(DownBatchLevel, this)); |
|
229 } |
|
230 else |
|
231 { |
|
232 iStack->PrepareToPushL(1); |
|
233 iBatchUndoHasBeenWaived = EFalse; |
|
234 CleanupStack::PushL(TCleanupItem(CloseBatch, this)); |
|
235 CBatchCommand* batch = CBatchCommand::NewL(); |
|
236 iCurrent = batch; |
|
237 iStack->Push(batch); |
|
238 } |
|
239 } |
|
240 |
|
241 TBool CCommandHistory::UndoHasBeenWaived() const |
|
242 { |
|
243 return iCurrent? iBatchUndoHasBeenWaived : EFalse; |
|
244 } |
|
245 |
|
246 void CCommandHistory::SetUndoWaived() |
|
247 { |
|
248 iBatchUndoHasBeenWaived = ETrue; |
|
249 } |
|
250 |
|
251 void CCommandHistory::Reset() |
|
252 { |
|
253 iStack->Reset(); |
|
254 iCurrent = 0; |
|
255 } |
|
256 |
|
257 void CCommandHistory::PrepareToAddCommandL(CCommand* aCommand) |
|
258 { |
|
259 if (iCurrent) |
|
260 iCurrent->PrepareToPushL(aCommand); |
|
261 else |
|
262 iStack->PrepareToPushL(1); |
|
263 } |
|
264 |
|
265 void CCommandHistory::AddCommand(CCommand* aCommand) |
|
266 { |
|
267 if (iCurrent) |
|
268 iCurrent->Push(aCommand); |
|
269 else |
|
270 iStack->Push(aCommand); |
|
271 if (!iCurrent) |
|
272 Prune(); |
|
273 } |
|
274 |
|
275 CSingleCommand* CCommandHistory::TopSingleCommand() const |
|
276 { |
|
277 CCommand* top = Top(); |
|
278 |
|
279 if (!top) |
|
280 return 0; |
|
281 |
|
282 // if the top of the undo stack is an empty batch, then we are starting a new |
|
283 // batch command and so do not want to combine. Otherwise, if the top is a batch |
|
284 // with elements, we want to see if we can combine with the top one. |
|
285 CBatchCommand* batch = top->Batch(); |
|
286 return batch? batch->Top() : top->Single(); |
|
287 } |
|
288 |
|
289 CCommand* CCommandHistory::Top() const |
|
290 { |
|
291 return iStack->Top(); |
|
292 } |
|
293 |
|
294 CCommand* CCommandHistory::Pop() |
|
295 { |
|
296 ASSERT(!iCurrent); |
|
297 return iStack->Pop(); |
|
298 } |
|
299 |
|
300 void CCommandHistory::Clean() |
|
301 { |
|
302 ASSERT(!iCurrent); |
|
303 CCommand* command = Top(); |
|
304 if (!command) |
|
305 return; |
|
306 CBatchCommand* batch = command->Batch(); |
|
307 if (!batch) |
|
308 return; |
|
309 if (batch->IsEmpty()) |
|
310 { |
|
311 delete Pop(); |
|
312 } |
|
313 } |
|
314 |
|
315 void CCommandHistory::SetBookmark() |
|
316 { |
|
317 iStack->SetBookmark(); |
|
318 } |
|
319 |
|
320 TBool CCommandHistory::IsAtBookmark() |
|
321 { |
|
322 return iStack->IsAtBookmark(); |
|
323 } |
|
324 |