|
1 /* |
|
2 * Copyright (c) 2002-2005 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: Implementation of XCFW Content tree |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include "xcfwtree.h" |
|
22 #include "xcfwnode.h" |
|
23 #include "xcfwpanic.h" |
|
24 |
|
25 // MACROS |
|
26 //Helper macro to cast MXCFWNode pointers to CXCFWNode |
|
27 #define WRAPNODE( aNode ) static_cast<CXCFWNode*>( aNode ) |
|
28 |
|
29 // ============================ MEMBER FUNCTIONS =============================== |
|
30 |
|
31 // ----------------------------------------------------------------------------- |
|
32 // CXCFWTree::CXCFWTree |
|
33 // C++ default constructor can NOT contain any code, that |
|
34 // might leave. |
|
35 // ----------------------------------------------------------------------------- |
|
36 // |
|
37 CXCFWTree::CXCFWTree() |
|
38 { |
|
39 } |
|
40 |
|
41 // ----------------------------------------------------------------------------- |
|
42 // CXCFWTree::ConstructL |
|
43 // Symbian 2nd phase constructor can leave. |
|
44 // ----------------------------------------------------------------------------- |
|
45 // |
|
46 void CXCFWTree::ConstructL() |
|
47 { |
|
48 } |
|
49 |
|
50 // ----------------------------------------------------------------------------- |
|
51 // CXCFWTree::NewL |
|
52 // Two-phased constructor. |
|
53 // ----------------------------------------------------------------------------- |
|
54 // |
|
55 EXPORT_C CXCFWTree* CXCFWTree::NewL() |
|
56 { |
|
57 CXCFWTree* self = new( ELeave ) CXCFWTree; |
|
58 |
|
59 CleanupStack::PushL( self ); |
|
60 self->ConstructL(); |
|
61 CleanupStack::Pop( self ); |
|
62 |
|
63 return self; |
|
64 } |
|
65 |
|
66 |
|
67 // Destructor |
|
68 EXPORT_C CXCFWTree::~CXCFWTree() |
|
69 { |
|
70 //delete dtd name buffer |
|
71 delete iDTDName; |
|
72 |
|
73 //delete node array |
|
74 iNodeList.ResetAndDestroy(); |
|
75 iNodeList.Close(); |
|
76 |
|
77 //reset node array for client |
|
78 iNodeListForClient.Reset(); |
|
79 iNodeListForClient.Close(); |
|
80 |
|
81 //Null root pointer (owned in the iNodeList array) |
|
82 iRoot = NULL; |
|
83 } |
|
84 |
|
85 |
|
86 // ----------------------------------------------------------------------------- |
|
87 // CXCFWTree::AddNodeL |
|
88 // this overload is for adding node under certain parent before certain child |
|
89 // ----------------------------------------------------------------------------- |
|
90 // |
|
91 EXPORT_C MXCFWNode* CXCFWTree::AddNodeL( |
|
92 CGECOObjectBase* aData, |
|
93 MXCFWNode* aParent, |
|
94 MXCFWNode* aInsertBefore ) |
|
95 { |
|
96 CleanupStack::PushL( aData ); |
|
97 __ASSERT_LEAVE( aParent && aData && aInsertBefore && |
|
98 aData->TypeIdentifier() != iRoot->Data()->TypeIdentifier() && |
|
99 aInsertBefore->Parent() == aParent, KErrArgument ); |
|
100 |
|
101 __ASSERT_LEAVE( !iLocked, KErrAccessDenied ); |
|
102 |
|
103 //Create new node and add to arrays. |
|
104 CXCFWNode* nodeToAdd = CXCFWNode::NewL( aData ); |
|
105 CleanupStack::Pop( aData ); |
|
106 CleanupStack::PushL( nodeToAdd ); |
|
107 User::LeaveIfError( iNodeList.Append( nodeToAdd ) ); |
|
108 CleanupStack::Pop( nodeToAdd ); |
|
109 |
|
110 //update node references |
|
111 nodeToAdd->SetParent( aParent ); |
|
112 nodeToAdd->SetNextSibling( aInsertBefore ); |
|
113 nodeToAdd->SetPrevSibling( aInsertBefore->PrevSibling() ); |
|
114 |
|
115 //if "insert before" -node has previous sibling, update that |
|
116 if ( aInsertBefore->PrevSibling() ) |
|
117 { |
|
118 WRAPNODE( aInsertBefore->PrevSibling() )->SetNextSibling( nodeToAdd ); |
|
119 } |
|
120 |
|
121 //set previous sibling |
|
122 WRAPNODE( aInsertBefore )->SetPrevSibling( nodeToAdd ); |
|
123 |
|
124 if( aParent->FirstChild() == aInsertBefore ) |
|
125 { |
|
126 WRAPNODE( aParent )->SetFirstChild( nodeToAdd ); |
|
127 } |
|
128 |
|
129 //Set client list dirty => will be updated on next Nodes() request. |
|
130 iClientListDirty = ETrue; |
|
131 |
|
132 return nodeToAdd; |
|
133 |
|
134 } |
|
135 |
|
136 // ----------------------------------------------------------------------------- |
|
137 // CXCFWTree::AddNodeL |
|
138 // this overload is for adding node under certain parent as last child |
|
139 // ----------------------------------------------------------------------------- |
|
140 // |
|
141 EXPORT_C MXCFWNode* CXCFWTree::AddNodeL( |
|
142 CGECOObjectBase* aData, |
|
143 MXCFWNode* aParent ) |
|
144 { |
|
145 CleanupStack::PushL( aData ); |
|
146 //Legality checks |
|
147 __ASSERT_LEAVE( aParent && aData && |
|
148 aData->TypeIdentifier() != iRoot->Data()->TypeIdentifier(), |
|
149 KErrArgument ); |
|
150 |
|
151 __ASSERT_LEAVE( !iLocked, KErrAccessDenied ); |
|
152 |
|
153 |
|
154 //Create new node and add to arrays |
|
155 CXCFWNode* nodeToAdd = CXCFWNode::NewL( aData ); |
|
156 CleanupStack::Pop( aData ); |
|
157 CleanupStack::PushL( nodeToAdd ); |
|
158 User::LeaveIfError( iNodeList.Append( nodeToAdd ) ); |
|
159 CleanupStack::Pop( nodeToAdd ); |
|
160 |
|
161 //set parent for new node |
|
162 nodeToAdd->SetParent( aParent ); |
|
163 |
|
164 //if parent has a last child |
|
165 if( aParent->LastChild() ) |
|
166 { |
|
167 nodeToAdd->SetPrevSibling( aParent->LastChild() ); |
|
168 WRAPNODE( aParent->LastChild() )->SetNextSibling( nodeToAdd ); |
|
169 } |
|
170 else |
|
171 { |
|
172 WRAPNODE( aParent )->SetFirstChild( nodeToAdd ); |
|
173 } |
|
174 |
|
175 //update last child of the parent |
|
176 WRAPNODE( aParent )->SetLastChild( nodeToAdd ); |
|
177 |
|
178 //Set client list dirty => will be updated on next Nodes() request. |
|
179 iClientListDirty = ETrue; |
|
180 |
|
181 return nodeToAdd; |
|
182 } |
|
183 |
|
184 // ----------------------------------------------------------------------------- |
|
185 // CXCFWTree::AddNodeL |
|
186 // this overload is for adding root node only |
|
187 // ----------------------------------------------------------------------------- |
|
188 // |
|
189 EXPORT_C MXCFWNode* CXCFWTree::AddNodeL( |
|
190 CGECOObjectBase* aData ) |
|
191 { |
|
192 CleanupStack::PushL( aData ); |
|
193 //if we already have a root, this is illegal |
|
194 __ASSERT_LEAVE( iRoot==NULL, KErrAlreadyExists ); |
|
195 |
|
196 __ASSERT_LEAVE( !iLocked, KErrAccessDenied ); |
|
197 |
|
198 //Create root node and add to arrays |
|
199 CXCFWNode* nodeToAdd = CXCFWNode::NewL( aData ); |
|
200 CleanupStack::Pop( aData ); |
|
201 CleanupStack::PushL( nodeToAdd ); |
|
202 User::LeaveIfError( iNodeList.Append( nodeToAdd ) ); |
|
203 CleanupStack::Pop( nodeToAdd ); |
|
204 |
|
205 //Set internal root member. |
|
206 iRoot = nodeToAdd; |
|
207 nodeToAdd = NULL; |
|
208 |
|
209 //Set client list dirty => will be updated on next Nodes() request. |
|
210 iClientListDirty = ETrue; |
|
211 |
|
212 return iRoot; |
|
213 } |
|
214 |
|
215 // ----------------------------------------------------------------------------- |
|
216 // CXCFWTree::GetChildNodesL |
|
217 // Put child nodes of the given parent to the given array |
|
218 // ----------------------------------------------------------------------------- |
|
219 // |
|
220 EXPORT_C void CXCFWTree::GetChildNodesL( |
|
221 MXCFWNode* aParent, |
|
222 RNodeArray& aNodeList) |
|
223 { |
|
224 |
|
225 __ASSERT_LEAVE( aParent != NULL, KErrArgument ); |
|
226 |
|
227 MXCFWNode* pointer = aParent->FirstChild(); |
|
228 while ( pointer ) |
|
229 { |
|
230 User::LeaveIfError( aNodeList.Append( pointer ) ); |
|
231 pointer = pointer->NextSibling(); |
|
232 } |
|
233 |
|
234 } |
|
235 |
|
236 // ----------------------------------------------------------------------------- |
|
237 // CXCFWTree::GetNodesOfTypeL |
|
238 // Put nodes that have dataobject of given type to given array. |
|
239 // In case of recursion, pre-order recursion is used |
|
240 // ----------------------------------------------------------------------------- |
|
241 // |
|
242 EXPORT_C void CXCFWTree::GetNodesOfTypeL( |
|
243 const TDesC& aType, |
|
244 RNodeArray& aNodeList, |
|
245 MXCFWNode* aParent, |
|
246 TBool aRecursive ) |
|
247 { |
|
248 |
|
249 __ASSERT_LEAVE( aParent != NULL, KErrArgument ); |
|
250 |
|
251 MXCFWNode* pointer = aParent->FirstChild(); |
|
252 |
|
253 while ( pointer ) |
|
254 { |
|
255 if ( pointer->Data()->TypeIdentifier().Compare( aType ) == 0 ) |
|
256 { |
|
257 User::LeaveIfError( aNodeList.Append( pointer ) ); |
|
258 } |
|
259 if ( aRecursive ) |
|
260 { |
|
261 GetNodesOfTypeL( aType, aNodeList, pointer, aRecursive ); |
|
262 } |
|
263 pointer = pointer->NextSibling(); |
|
264 } |
|
265 |
|
266 } |
|
267 |
|
268 // ----------------------------------------------------------------------------- |
|
269 // CXCFWTree::MoveNodeL |
|
270 // Moves a node in tree and updates the relative nodes in both original and |
|
271 // new location. |
|
272 // ----------------------------------------------------------------------------- |
|
273 // |
|
274 EXPORT_C void CXCFWTree::MoveNodeL( |
|
275 MXCFWNode* aNodeToMove, |
|
276 MXCFWNode* aNewParent, |
|
277 MXCFWNode* aInsertBefore ) |
|
278 { |
|
279 |
|
280 // assure parameter legality |
|
281 __ASSERT_LEAVE( aNodeToMove && aNewParent && |
|
282 aNodeToMove != iRoot && aInsertBefore != iRoot && |
|
283 aNodeToMove != aNewParent, |
|
284 KErrArgument ); |
|
285 |
|
286 __ASSERT_LEAVE( !iLocked, KErrAccessDenied ); |
|
287 |
|
288 |
|
289 //if "insert before" node is child node of the given parent, move is illegal |
|
290 if ( aInsertBefore && aInsertBefore->Parent() != aNewParent ) |
|
291 { |
|
292 User::Leave( KErrArgument ); |
|
293 } |
|
294 |
|
295 MXCFWNode* check = aNewParent->Parent(); |
|
296 while ( check ) |
|
297 { |
|
298 //if user tries to move a node under itself (it is among the parents |
|
299 // of the given new parent) we'll leave |
|
300 if ( check == aNodeToMove ) |
|
301 { |
|
302 User::Leave( KErrArgument ); |
|
303 } |
|
304 check = check->Parent(); |
|
305 } |
|
306 check = NULL; |
|
307 |
|
308 //first update old parent if necessary |
|
309 if ( aNodeToMove->Parent()->FirstChild() == aNodeToMove ) |
|
310 { |
|
311 WRAPNODE( aNodeToMove->Parent() )->SetFirstChild( |
|
312 aNodeToMove->NextSibling() ); |
|
313 } |
|
314 if ( aNodeToMove->Parent()->LastChild() == aNodeToMove ) |
|
315 { |
|
316 WRAPNODE( aNodeToMove->Parent() )->SetLastChild( |
|
317 aNodeToMove->PrevSibling() ); |
|
318 } |
|
319 |
|
320 //update old siblings |
|
321 if ( aNodeToMove->PrevSibling() ) |
|
322 { |
|
323 WRAPNODE( aNodeToMove->PrevSibling())->SetNextSibling( |
|
324 aNodeToMove->NextSibling() ); |
|
325 } |
|
326 |
|
327 if ( aNodeToMove->NextSibling() ) |
|
328 { |
|
329 WRAPNODE( aNodeToMove->NextSibling() )->SetPrevSibling( |
|
330 aNodeToMove->PrevSibling() ); |
|
331 } |
|
332 |
|
333 //set new parent: |
|
334 WRAPNODE( aNodeToMove )->SetParent( aNewParent ); |
|
335 |
|
336 //update new siblings |
|
337 if ( aInsertBefore ) |
|
338 { |
|
339 |
|
340 //if "insert before" -node has a sibling before it, we update that |
|
341 if ( aInsertBefore->PrevSibling() ) |
|
342 { |
|
343 WRAPNODE( aInsertBefore->PrevSibling() )->SetNextSibling( |
|
344 aNodeToMove ); |
|
345 } |
|
346 else |
|
347 //no previous sibling => insertbefore is the first child of new parent |
|
348 { |
|
349 WRAPNODE( aNewParent )->SetFirstChild( aNodeToMove ); |
|
350 } |
|
351 WRAPNODE( aNodeToMove )->SetPrevSibling( aInsertBefore->PrevSibling() ); |
|
352 WRAPNODE( aNodeToMove )->SetNextSibling( aInsertBefore ); |
|
353 WRAPNODE( aInsertBefore )->SetPrevSibling( aNodeToMove ); |
|
354 } |
|
355 else |
|
356 { |
|
357 //if new parent had children |
|
358 if ( aNewParent->LastChild() ) |
|
359 { |
|
360 WRAPNODE( aNewParent->LastChild() )->SetNextSibling( aNodeToMove ); |
|
361 WRAPNODE( aNodeToMove )->SetPrevSibling( aNewParent->LastChild() ); |
|
362 WRAPNODE( aNewParent )->SetLastChild( aNodeToMove ); |
|
363 WRAPNODE( aNodeToMove )->SetNextSibling(NULL); |
|
364 } |
|
365 else //no children before |
|
366 { |
|
367 WRAPNODE( aNewParent )->SetFirstChild( aNodeToMove ); |
|
368 WRAPNODE( aNewParent )->SetLastChild( aNodeToMove ); |
|
369 WRAPNODE( aNodeToMove )->SetPrevSibling( NULL ); |
|
370 WRAPNODE( aNodeToMove )->SetNextSibling( NULL ); |
|
371 } |
|
372 } |
|
373 |
|
374 //Set client list dirty => will be updated on next Nodes() request. |
|
375 iClientListDirty = ETrue; |
|
376 |
|
377 } |
|
378 |
|
379 // ----------------------------------------------------------------------------- |
|
380 // CXCFWTree::Nodes |
|
381 // return tree nodes as array of MXCFWNode pointers |
|
382 // ----------------------------------------------------------------------------- |
|
383 // |
|
384 EXPORT_C RNodeArray& CXCFWTree::Nodes() |
|
385 { |
|
386 |
|
387 //see if we should update the MXCFWNode array to reflect the new |
|
388 if ( iClientListDirty ) |
|
389 { |
|
390 |
|
391 if ( iNodeListForClient.Count() > 0 ) |
|
392 { |
|
393 iNodeListForClient.Reset(); |
|
394 } |
|
395 |
|
396 TInt count = iNodeList.Count(); |
|
397 for ( TInt i = 0; i < count; i++ ) |
|
398 { |
|
399 iNodeListForClient.Append( (MXCFWNode*)iNodeList[i] ); |
|
400 } |
|
401 iClientListDirty = EFalse; |
|
402 } |
|
403 |
|
404 return iNodeListForClient; |
|
405 } |
|
406 |
|
407 |
|
408 // ----------------------------------------------------------------------------- |
|
409 // CXCFWTree::RemoveNodeL |
|
410 // Removes a node from tree by updating all relative nodes and removing from |
|
411 // arrays. |
|
412 // ----------------------------------------------------------------------------- |
|
413 // |
|
414 EXPORT_C void CXCFWTree::RemoveNodeL( |
|
415 MXCFWNode* aNodeToRemove ) |
|
416 { |
|
417 |
|
418 __ASSERT_LEAVE( aNodeToRemove != NULL, KErrArgument ); |
|
419 |
|
420 __ASSERT_LEAVE( !iLocked, KErrAccessDenied ); |
|
421 |
|
422 if ( iRoot != aNodeToRemove ) |
|
423 { |
|
424 //update related nodes before removal, unless removing root node. |
|
425 if ( aNodeToRemove->PrevSibling() ) |
|
426 { |
|
427 WRAPNODE( aNodeToRemove->PrevSibling() )->SetNextSibling( |
|
428 aNodeToRemove->NextSibling() ); |
|
429 } |
|
430 |
|
431 if ( aNodeToRemove->NextSibling() ) |
|
432 { |
|
433 WRAPNODE( aNodeToRemove->NextSibling() )->SetPrevSibling( |
|
434 aNodeToRemove->PrevSibling() ); |
|
435 } |
|
436 |
|
437 if ( aNodeToRemove->Parent()->FirstChild() == aNodeToRemove ) |
|
438 { |
|
439 WRAPNODE( aNodeToRemove->Parent() )->SetFirstChild( |
|
440 aNodeToRemove->NextSibling() ); |
|
441 } |
|
442 |
|
443 if ( aNodeToRemove->Parent()->LastChild() == aNodeToRemove ) |
|
444 { |
|
445 WRAPNODE( aNodeToRemove->Parent() )->SetLastChild( |
|
446 aNodeToRemove->PrevSibling() ); |
|
447 } |
|
448 } |
|
449 else |
|
450 { |
|
451 //root was removed. |
|
452 iRoot = NULL; |
|
453 } |
|
454 |
|
455 //Set client list dirty => will be updated on next Nodes() request. |
|
456 iClientListDirty = ETrue; |
|
457 |
|
458 RemoveNodeRecursiveL( aNodeToRemove ); |
|
459 |
|
460 } |
|
461 |
|
462 |
|
463 // ----------------------------------------------------------------------------- |
|
464 // CXCFWTree::RemoveFromArray |
|
465 // Removes node pointer from CXCFWNode and MXCFWNode pointer arrays. |
|
466 // Deletes from CXCFWNode array as well. |
|
467 // ----------------------------------------------------------------------------- |
|
468 // |
|
469 void CXCFWTree::RemoveFromNodeList( |
|
470 MXCFWNode* aNode ) |
|
471 { |
|
472 |
|
473 //remove node from the pointer array. |
|
474 TInt i = iNodeList.Count() - 1 ; |
|
475 for ( ;i>=0 && aNode != iNodeList[i] ; i-- ){} |
|
476 if ( i>=0 ) |
|
477 { |
|
478 //delete object |
|
479 delete iNodeList[i]; |
|
480 //remove from pointer arrays. |
|
481 iNodeList.Remove(i); |
|
482 } |
|
483 |
|
484 } |
|
485 |
|
486 // ----------------------------------------------------------------------------- |
|
487 // CXCFWTree::RemoveNodeRecursiveL |
|
488 // Post-order recursion is used to make sure that no orhpan nodes are left |
|
489 // floating. |
|
490 // ----------------------------------------------------------------------------- |
|
491 // |
|
492 void CXCFWTree::RemoveNodeRecursiveL( |
|
493 MXCFWNode* aNode ) |
|
494 { |
|
495 |
|
496 __ASSERT_LEAVE ( aNode != NULL, KErrArgument ); |
|
497 |
|
498 MXCFWNode* pointer = aNode->FirstChild(); |
|
499 |
|
500 while ( pointer ) |
|
501 { |
|
502 MXCFWNode* temp = pointer->NextSibling(); |
|
503 RemoveNodeRecursiveL( pointer ); |
|
504 pointer = temp; |
|
505 } |
|
506 |
|
507 RemoveFromNodeList( aNode ); |
|
508 |
|
509 } |
|
510 |
|
511 |
|
512 // ----------------------------------------------------------------------------- |
|
513 // CXCFWTree::Root |
|
514 // Returns MXCFWNode pointer to root node. |
|
515 // ----------------------------------------------------------------------------- |
|
516 // |
|
517 EXPORT_C MXCFWNode* CXCFWTree::Root() |
|
518 { |
|
519 return iRoot; |
|
520 } |
|
521 |
|
522 EXPORT_C void CXCFWTree::SetLocked( TBool aLockStatus ) |
|
523 { |
|
524 iLocked = aLockStatus; |
|
525 } |
|
526 |
|
527 EXPORT_C TBool CXCFWTree::IsLocked() |
|
528 { |
|
529 return iLocked; |
|
530 } |
|
531 |
|
532 const TDesC& CXCFWTree::DTDName() |
|
533 { |
|
534 if ( !iDTDName ) |
|
535 { |
|
536 return KNullDesC; |
|
537 } |
|
538 else |
|
539 { |
|
540 return *iDTDName; |
|
541 } |
|
542 } |
|
543 |
|
544 void CXCFWTree::SetDTDNameL( const TDesC& aName ) |
|
545 { |
|
546 delete iDTDName; |
|
547 iDTDName = NULL; |
|
548 iDTDName = aName.AllocL(); |
|
549 } |
|
550 |
|
551 // End of File |