|
1 /* |
|
2 * Copyright (c) 2008 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: Base class for AppInfo and PackageInfo arrays |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "appmngr2infoarray.h" // CAppMngr2InfoArray |
|
20 #include <appmngr2debugutils.h> // FLOG macros |
|
21 |
|
22 const TInt KGranularity = 32; |
|
23 |
|
24 |
|
25 // ======== LOCAL FUNCTIONS ========= |
|
26 |
|
27 // --------------------------------------------------------------------------- |
|
28 // CompareInfoNamesC |
|
29 // --------------------------------------------------------------------------- |
|
30 // Compares two InfoBase objects and defines the order how they are displayed |
|
31 // in the UI (in installed applications list or in installation files list). |
|
32 // Returns positive integer if aInfo1 > aInfo2 (in defined/alphabetical order), |
|
33 // zero if aInfo == aInfo2, and negative integer if aInfo1 < aInfo2. |
|
34 TInt CompareInfoNamesC( const CAppMngr2InfoBase& aInfo1, const CAppMngr2InfoBase& aInfo2 ) |
|
35 { |
|
36 // IsShowOnTop() must denote "less than" to get the item be displayed before others. |
|
37 // If IsShowOnTop()==ETrue then item is less than item having IsShowOnTop()==EFalse. |
|
38 TInt result = ( aInfo2.IsShowOnTop() - aInfo1.IsShowOnTop() ); |
|
39 if( !result ) |
|
40 { |
|
41 result = aInfo1.Name().CompareC( aInfo2.Name() ); |
|
42 if( !result ) |
|
43 { |
|
44 // Compare also locations if the names are the same, as otherwise the order of |
|
45 // two items having the same name changes in MoveCachedItemsToArrayInOrderL(). |
|
46 // Memory card location is "greater than" location in phone internal memory. |
|
47 result = ( aInfo1.Location() - aInfo2.Location() ); |
|
48 } |
|
49 } |
|
50 return result; |
|
51 } |
|
52 |
|
53 |
|
54 // ======== MEMBER FUNCTIONS ======== |
|
55 |
|
56 // --------------------------------------------------------------------------- |
|
57 // CAppMngr2InfoArray::CAppMngr2InfoArray() |
|
58 // --------------------------------------------------------------------------- |
|
59 // |
|
60 CAppMngr2InfoArray::CAppMngr2InfoArray( MAppMngr2InfoArrayObserver& aObserver ) : |
|
61 iObserver( aObserver), iArray( KGranularity ), iCache( KGranularity ), |
|
62 iAlphabeticalOrder( CompareInfoNamesC ), iQuickRefreshes( ETrue ) |
|
63 { |
|
64 } |
|
65 |
|
66 // --------------------------------------------------------------------------- |
|
67 // CAppMngr2InfoArray::~CAppMngr2InfoArray() |
|
68 // --------------------------------------------------------------------------- |
|
69 // |
|
70 CAppMngr2InfoArray::~CAppMngr2InfoArray() |
|
71 { |
|
72 iArray.ResetAndDestroy(); |
|
73 iCache.ResetAndDestroy(); |
|
74 } |
|
75 |
|
76 // --------------------------------------------------------------------------- |
|
77 // CAppMngr2InfoArray::At() |
|
78 // --------------------------------------------------------------------------- |
|
79 // |
|
80 CAppMngr2InfoBase* CAppMngr2InfoArray::At( TInt aIndex ) const |
|
81 { |
|
82 if( IsCacheUsed() ) |
|
83 { |
|
84 return iCache[ aIndex ]; |
|
85 } |
|
86 return iArray[ aIndex ]; |
|
87 } |
|
88 |
|
89 // --------------------------------------------------------------------------- |
|
90 // CAppMngr2InfoArray::Count() |
|
91 // --------------------------------------------------------------------------- |
|
92 // |
|
93 TInt CAppMngr2InfoArray::Count() const |
|
94 { |
|
95 if( IsCacheUsed() ) |
|
96 { |
|
97 return iCache.Count(); |
|
98 } |
|
99 return iArray.Count(); |
|
100 } |
|
101 |
|
102 // --------------------------------------------------------------------------- |
|
103 // CAppMngr2InfoArray::IncrementCacheUseL() |
|
104 // --------------------------------------------------------------------------- |
|
105 // |
|
106 void CAppMngr2InfoArray::IncrementCacheUseL() |
|
107 { |
|
108 if( !iUseCache ) |
|
109 { |
|
110 // First time - take the cache in use. This starts adding new |
|
111 // items to the CAppMngr2InfoArray. New items are always added |
|
112 // to iArray, and iCache is displayed during adding. |
|
113 if( iForceCacheUse ) |
|
114 { |
|
115 // Cache already used - initialize iArray for new items. |
|
116 iArray.ResetAndDestroy(); |
|
117 |
|
118 // Make sure that observer is notified even if no items |
|
119 // are added to iArray (e.g. "last item deleted" -case). |
|
120 iArrayChangedObserverNeedsNotification = ETrue; |
|
121 } |
|
122 else |
|
123 { |
|
124 // Cache not used - move items to cache and start using it. |
|
125 MoveItemsToCacheMaintainingOrderL(); |
|
126 |
|
127 // Reset flag - need to know if cache is forced in use |
|
128 // while it is still in use because of this increment. |
|
129 iForceCacheUseWhenAddingComplete = EFalse; |
|
130 } |
|
131 } |
|
132 iUseCache++; |
|
133 } |
|
134 |
|
135 // --------------------------------------------------------------------------- |
|
136 // CAppMngr2InfoArray::IncrementCacheUseStartingNewRoundL() |
|
137 // --------------------------------------------------------------------------- |
|
138 // |
|
139 void CAppMngr2InfoArray::IncrementCacheUseStartingNewRoundL() |
|
140 { |
|
141 if( iUseCache || iForceCacheUse ) |
|
142 { |
|
143 // Cache already used - initialize iArray for new items. |
|
144 iArray.ResetAndDestroy(); |
|
145 iArrayChangedObserverNeedsNotification = ETrue; |
|
146 |
|
147 if( iQuickRefreshes ) |
|
148 { |
|
149 // Touch luck - cache is not really used (in order to |
|
150 // show the first items quickly on startup) and hence |
|
151 // it is now necessary to show empty list to the user. |
|
152 // If iObserver would not be notified, there would be |
|
153 // USER 130 panics when UI would try to access iArray |
|
154 // items that are deleted. |
|
155 iObserver.ArrayContentChanged( this, iUseCache + 1 ); |
|
156 iArrayChangedObserverNeedsNotification = EFalse; |
|
157 } |
|
158 } |
|
159 IncrementCacheUseL(); |
|
160 } |
|
161 |
|
162 // --------------------------------------------------------------------------- |
|
163 // CAppMngr2InfoArray::DecrementCacheUse() |
|
164 // --------------------------------------------------------------------------- |
|
165 // |
|
166 void CAppMngr2InfoArray::DecrementCacheUse() |
|
167 { |
|
168 if( iUseCache > 0 ) |
|
169 { |
|
170 iUseCache--; |
|
171 |
|
172 if( !iUseCache ) |
|
173 { |
|
174 // Quick refreshes are enabled on startup, but they need to be |
|
175 // turned off when the first item adding round is complete. |
|
176 // After the first round the cache is used to handle array |
|
177 // content changes. |
|
178 if( iQuickRefreshes ) |
|
179 { |
|
180 iQuickRefreshes = EFalse; |
|
181 } |
|
182 |
|
183 // If adding is now complete, check if there is a request to |
|
184 // force cache on. Note that iForceInUse cannot be set when |
|
185 // cache is already in use (because items are added to iArray), |
|
186 // otherwise partial list would be in iCache and the rest in |
|
187 // iArray. This is why force cache in use is enabled only after |
|
188 // the addition is complete. |
|
189 if( iForceCacheUseWhenAddingComplete ) |
|
190 { |
|
191 iForceCacheUse = ETrue; |
|
192 iForceCacheUseWhenAddingComplete = EFalse; |
|
193 } |
|
194 } |
|
195 |
|
196 // Notify UI if cache is not used any more (or quickrefreshing is on) |
|
197 if( !IsCacheUsed() ) |
|
198 { |
|
199 NotifyObserver(); |
|
200 } |
|
201 } |
|
202 } |
|
203 |
|
204 // --------------------------------------------------------------------------- |
|
205 // CAppMngr2InfoArray::DisableRefreshNotificationsL() |
|
206 // --------------------------------------------------------------------------- |
|
207 // |
|
208 void CAppMngr2InfoArray::DisableRefreshNotificationsL() |
|
209 { |
|
210 // Refresh notifications are disabled by forcing cache on. All changes go |
|
211 // to the iArray and current iCache content is displayed unitl notifications |
|
212 // are enabled again. Observer is not called while refreshes are disabled. |
|
213 if( !iForceCacheUse ) |
|
214 { |
|
215 if( iUseCache ) |
|
216 { |
|
217 // Cannot force cache in use now because items are still being added |
|
218 // to iArray. This would result partial list to be in iCache and the |
|
219 // rest of items in iArray. Later when deletions are enabled, only the |
|
220 // items in iArray would be displayed. So, set a flag that forces cache |
|
221 // on when item additions are complete, so that observer is notified |
|
222 // only after deletions are enabled again. |
|
223 iForceCacheUseWhenAddingComplete = ETrue; |
|
224 } |
|
225 else |
|
226 { |
|
227 // Set cache in use |
|
228 MoveItemsToCacheMaintainingOrderL(); |
|
229 iForceCacheUse = ETrue; |
|
230 } |
|
231 } |
|
232 } |
|
233 |
|
234 // --------------------------------------------------------------------------- |
|
235 // CAppMngr2InfoArray::EnableRefreshNotificationsL() |
|
236 // --------------------------------------------------------------------------- |
|
237 // |
|
238 void CAppMngr2InfoArray::EnableRefreshNotificationsL() |
|
239 { |
|
240 // It is safe to call EnableRefreshNotificationsL() many times, even if |
|
241 // notifications have not been disabled first. |
|
242 iForceCacheUseWhenAddingComplete = EFalse; |
|
243 if( iForceCacheUse ) |
|
244 { |
|
245 iForceCacheUse = EFalse; |
|
246 if( !iUseCache ) |
|
247 { |
|
248 // Refresh notifications were disabled by moving items to iCache. If no |
|
249 // new items were added to iArray while notifications were disabled, |
|
250 // then those moved items must be moved back to iArray again. Otherwise |
|
251 // disabling cache would show just an empty list. If new items were added |
|
252 // while refresh notifications were disabled, then observer needs |
|
253 // notification and cache content can be ignored, as new content is |
|
254 // already available in iArray. |
|
255 if( iArrayChangedObserverNeedsNotification ) |
|
256 { |
|
257 NotifyObserver(); |
|
258 } |
|
259 else |
|
260 { |
|
261 MoveCachedItemsToArrayInOrderL(); |
|
262 } |
|
263 } |
|
264 } |
|
265 } |
|
266 |
|
267 // --------------------------------------------------------------------------- |
|
268 // CAppMngr2InfoArray::AddItemInOrderL() |
|
269 // --------------------------------------------------------------------------- |
|
270 // |
|
271 void CAppMngr2InfoArray::AddItemInOrderL( CAppMngr2InfoBase* aInfo ) |
|
272 { |
|
273 if( aInfo ) |
|
274 { |
|
275 FLOG( "CAppMngr2InfoArray::AddItemInOrderL( %S )", &( aInfo->Name() ) ); |
|
276 |
|
277 // All items are added to iArray and iCache is used while the changes |
|
278 // are not wanted to be seen via Count() and At() functions. Observer |
|
279 // is notified when the iArray is taken in use. |
|
280 iArray.InsertInOrderAllowRepeatsL( aInfo, iAlphabeticalOrder ); |
|
281 if( iForceCacheUse || iForceCacheUseWhenAddingComplete ) |
|
282 { |
|
283 iArrayChangedObserverNeedsNotification = ETrue; |
|
284 } |
|
285 } |
|
286 } |
|
287 |
|
288 // --------------------------------------------------------------------------- |
|
289 // CAppMngr2InfoArray::ImmediateDelete() |
|
290 // --------------------------------------------------------------------------- |
|
291 // |
|
292 void CAppMngr2InfoArray::ImmediateDelete( CAppMngr2InfoBase* aInfo ) |
|
293 { |
|
294 FLOG( "CAppMngr2InfoArray::ImmediateDelete( 0x%08x )", aInfo ); |
|
295 |
|
296 RPointerArray<CAppMngr2InfoBase>* array; |
|
297 if( IsCacheUsed() ) |
|
298 { |
|
299 array = &iCache; |
|
300 } |
|
301 else |
|
302 { |
|
303 array = &iArray; |
|
304 } |
|
305 |
|
306 TBool found = EFalse; |
|
307 TInt count = array->Count(); |
|
308 for( TInt index = 0; index < count && !found; index++ ) |
|
309 { |
|
310 if( ( *array )[ index ] == aInfo ) |
|
311 { |
|
312 array->Remove( index ); |
|
313 delete aInfo; |
|
314 found = ETrue; |
|
315 } |
|
316 } |
|
317 |
|
318 if( found ) |
|
319 { |
|
320 iObserver.ArrayContentChanged( this, iUseCache ); |
|
321 } |
|
322 } |
|
323 |
|
324 // --------------------------------------------------------------------------- |
|
325 // CAppMngr2InfoArray::MoveItemsToCacheMaintainingOrderL() |
|
326 // --------------------------------------------------------------------------- |
|
327 // |
|
328 void CAppMngr2InfoArray::MoveItemsToCacheMaintainingOrderL() |
|
329 { |
|
330 // Move items from iArray to iCache maintaining order. |
|
331 iCache.ResetAndDestroy(); |
|
332 TInt count = iArray.Count(); |
|
333 for( TInt index = count - 1; index >= 0; index-- ) |
|
334 { |
|
335 iCache.InsertL( iArray[ index ], 0 ); |
|
336 iArray.Remove( index ); |
|
337 } |
|
338 iArray.ResetAndDestroy(); |
|
339 } |
|
340 |
|
341 // --------------------------------------------------------------------------- |
|
342 // CAppMngr2InfoArray::MoveCachedItemsToArrayInOrderL() |
|
343 // --------------------------------------------------------------------------- |
|
344 // |
|
345 void CAppMngr2InfoArray::MoveCachedItemsToArrayInOrderL() |
|
346 { |
|
347 // Move items from iCache to iArray using proper order. There may be |
|
348 // new items in iArray hence it is not possible to simply move items |
|
349 // as in MoveItemsToCacheMaintainingOrderL(). |
|
350 TInt count = iCache.Count(); |
|
351 for( TInt index = count - 1; index >= 0; index-- ) |
|
352 { |
|
353 iArray.InsertInOrderAllowRepeatsL( iCache[ index ], iAlphabeticalOrder ); |
|
354 iCache.Remove( index ); |
|
355 } |
|
356 iCache.ResetAndDestroy(); |
|
357 } |
|
358 |
|
359 // --------------------------------------------------------------------------- |
|
360 // CAppMngr2InfoArray::NotifyObserver() |
|
361 // --------------------------------------------------------------------------- |
|
362 // |
|
363 void CAppMngr2InfoArray::NotifyObserver() |
|
364 { |
|
365 iObserver.ArrayContentChanged( this, iUseCache ); |
|
366 iArrayChangedObserverNeedsNotification = EFalse; |
|
367 iCache.ResetAndDestroy(); |
|
368 } |
|
369 |
|
370 // --------------------------------------------------------------------------- |
|
371 // CAppMngr2InfoArray::IsCacheUsed() |
|
372 // --------------------------------------------------------------------------- |
|
373 // |
|
374 TBool CAppMngr2InfoArray::IsCacheUsed() const |
|
375 { |
|
376 // New items are added to iArray and static old content may be displayed |
|
377 // from iCache while iArray is being updated. Priorities: 1) cache forced |
|
378 // in use, 2) quick refreshes, and 3) normal inc/dec cache usage. If cache |
|
379 // is forced in use, it prevents also changes that quick refreshes might |
|
380 // otherwise display. If quick refreshing is enabled, then item additions |
|
381 // to iArray are visible to observer, although normally iCache would be used. |
|
382 if( iForceCacheUse ) |
|
383 { |
|
384 return ETrue; |
|
385 } |
|
386 if( iQuickRefreshes ) |
|
387 { |
|
388 return EFalse; |
|
389 } |
|
390 return ( iUseCache > 0 ); |
|
391 } |
|
392 |