|
1 /* |
|
2 ============================================================================ |
|
3 Name : NPRStoryListBox.cpp |
|
4 Author : Symsource |
|
5 |
|
6 Copyright (c) 2009 Symbian Foundation Ltd |
|
7 This component and the accompanying materials are made available |
|
8 under the terms of the License "Eclipse Public License v1.0" |
|
9 which accompanies this distribution, and is available |
|
10 at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
11 |
|
12 Initial Contributors: |
|
13 - Symsource |
|
14 |
|
15 Contributors: |
|
16 - Symsource |
|
17 |
|
18 Description : Container for Series60 double style list box to show the NPR's story list |
|
19 ============================================================================ |
|
20 */ |
|
21 |
|
22 #include <barsread.h> |
|
23 #include <aknlists.h> |
|
24 #include <akniconarray.h> |
|
25 #include <NPR_0xEEB0E481.rsg> |
|
26 #include <list_icons.mbg> |
|
27 |
|
28 #include "NPRStoryListBox.h" |
|
29 #include "NPRStoryListBoxView.h" |
|
30 #include "NPR.hrh" |
|
31 #include "NPRAppUi.h" |
|
32 #include "NPRAppEngine.h" |
|
33 #include "NPRHtmlCreator.h" |
|
34 |
|
35 _LIT(KStringHeader, "%d\t%S\t%S" ); |
|
36 _LIT(KTestUiFile, "\\resource\\apps\\list_icons.mbm"); |
|
37 |
|
38 /** |
|
39 * Construct the control (first phase). |
|
40 * Creates an instance and initializes it. |
|
41 * Instance is not left on cleanup stack. |
|
42 * @param aRect bounding rectangle |
|
43 * @param aParent owning parent, or NULL |
|
44 * @param aCommandObserver command observer |
|
45 * @return initialized instance of CNPRStoryListBox |
|
46 */ |
|
47 CNPRStoryListBox* CNPRStoryListBox::NewL( |
|
48 const TRect& aRect, |
|
49 const CCoeControl* aParent, |
|
50 MEikCommandObserver* aCommandObserver ) |
|
51 { |
|
52 CNPRStoryListBox* self = CNPRStoryListBox::NewLC( |
|
53 aRect, |
|
54 aParent, |
|
55 aCommandObserver ); |
|
56 CleanupStack::Pop( self ); |
|
57 return self; |
|
58 } |
|
59 |
|
60 /** |
|
61 * Construct the control (first phase). |
|
62 * Creates an instance and initializes it. |
|
63 * Instance is left on cleanup stack. |
|
64 * @param aRect The rectangle for this window |
|
65 * @param aParent owning parent, or NULL |
|
66 * @param aCommandObserver command observer |
|
67 * @return new instance of CNPRStoryListBox |
|
68 */ |
|
69 CNPRStoryListBox* CNPRStoryListBox::NewLC( |
|
70 const TRect& aRect, |
|
71 const CCoeControl* aParent, |
|
72 MEikCommandObserver* aCommandObserver ) |
|
73 { |
|
74 CNPRStoryListBox* self = new ( ELeave ) CNPRStoryListBox(); |
|
75 CleanupStack::PushL( self ); |
|
76 self->ConstructL( aRect, aParent, aCommandObserver ); |
|
77 return self; |
|
78 } |
|
79 |
|
80 /** |
|
81 * First phase of Symbian two-phase construction. Should not |
|
82 * contain any code that could leave. |
|
83 */ |
|
84 CNPRStoryListBox::CNPRStoryListBox() |
|
85 { |
|
86 iListBox = NULL; |
|
87 iStoryArray = static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())->Engine().Stories(); |
|
88 } |
|
89 /** |
|
90 * Destroy child controls. |
|
91 */ |
|
92 CNPRStoryListBox::~CNPRStoryListBox() |
|
93 { |
|
94 delete iHtmlCreator; |
|
95 delete iListBox; |
|
96 iListBox = NULL; |
|
97 } |
|
98 |
|
99 /** |
|
100 * Construct the control (second phase). |
|
101 * Creates a window to contain the controls and activates it. |
|
102 * @param aRect bounding rectangle |
|
103 * @param aCommandObserver command observer |
|
104 * @param aParent owning parent, or NULL |
|
105 */ |
|
106 void CNPRStoryListBox::ConstructL( |
|
107 const TRect& aRect, |
|
108 const CCoeControl* aParent, |
|
109 MEikCommandObserver* aCommandObserver ) |
|
110 { |
|
111 if ( aParent == NULL ) |
|
112 { |
|
113 CreateWindowL(); |
|
114 } |
|
115 else |
|
116 { |
|
117 SetContainerWindowL( *aParent ); |
|
118 } |
|
119 iFocusControl = NULL; |
|
120 iCommandObserver = aCommandObserver; |
|
121 iHtmlCreator = CNPRHtmlCreator::NewL(); |
|
122 |
|
123 InitializeControlsL(); |
|
124 SetRect( aRect ); |
|
125 ActivateL(); |
|
126 } |
|
127 |
|
128 /** |
|
129 * Return the number of controls in the container (override) |
|
130 * @return count |
|
131 */ |
|
132 TInt CNPRStoryListBox::CountComponentControls() const |
|
133 { |
|
134 return ( int ) ELastControl; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Get the control with the given index (override) |
|
139 * @param aIndex Control index [0...n) (limited by #CountComponentControls) |
|
140 * @return Pointer to control |
|
141 */ |
|
142 CCoeControl* CNPRStoryListBox::ComponentControl( TInt aIndex ) const |
|
143 { |
|
144 switch(aIndex) |
|
145 { |
|
146 case EListBox: |
|
147 return iListBox; |
|
148 } |
|
149 return NULL; |
|
150 } |
|
151 |
|
152 /** |
|
153 * Handle resizing of the container. This implementation will lay out |
|
154 * full-sized controls like list boxes for any screen size, and will layout |
|
155 * labels, editors, etc. to the size they were given in the UI designer. |
|
156 * This code will need to be modified to adjust arbitrary controls to |
|
157 * any screen size. |
|
158 */ |
|
159 void CNPRStoryListBox::SizeChanged() |
|
160 { |
|
161 CCoeControl::SizeChanged(); |
|
162 LayoutControls(); |
|
163 } |
|
164 |
|
165 /** |
|
166 * Layout components as specified in the UI Designer |
|
167 */ |
|
168 void CNPRStoryListBox::LayoutControls() |
|
169 { |
|
170 iListBox->SetExtent( TPoint( 0, 0 ), iListBox->MinimumSize() ); |
|
171 } |
|
172 |
|
173 /** |
|
174 * Handle key events. |
|
175 */ |
|
176 TKeyResponse CNPRStoryListBox::OfferKeyEventL( |
|
177 const TKeyEvent& aKeyEvent, |
|
178 TEventCode aType ) |
|
179 { |
|
180 if ( aKeyEvent.iCode == EKeyLeftArrow |
|
181 || aKeyEvent.iCode == EKeyRightArrow ) |
|
182 { |
|
183 // Listbox takes all events even if it doesn't use them |
|
184 return EKeyWasNotConsumed; |
|
185 } |
|
186 |
|
187 if ( iFocusControl != NULL && aKeyEvent.iCode == EKeyDevice3) |
|
188 { |
|
189 ShowSelectedStoryL(); |
|
190 return EKeyWasConsumed; |
|
191 } |
|
192 |
|
193 if ( iFocusControl != NULL |
|
194 && iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed ) |
|
195 { |
|
196 return EKeyWasConsumed; |
|
197 } |
|
198 return CCoeControl::OfferKeyEventL( aKeyEvent, aType ); |
|
199 } |
|
200 |
|
201 /** |
|
202 * Initialize each control upon creation. |
|
203 */ |
|
204 void CNPRStoryListBox::InitializeControlsL() |
|
205 { |
|
206 iListBox = new ( ELeave ) CAknDoubleLargeStyleListBox; |
|
207 iListBox->SetContainerWindowL( *this ); |
|
208 { |
|
209 TResourceReader reader; |
|
210 iEikonEnv->CreateResourceReaderLC( reader, R_NPRSTORY_LIST_BOX_LIST_BOX ); |
|
211 iListBox->ConstructFromResourceL( reader ); |
|
212 CleanupStack::PopAndDestroy(); // reader internal state |
|
213 } |
|
214 // the listbox owns the items in the list and will free them |
|
215 iListBox->Model()->SetOwnershipType( ELbmOwnsItemArray ); |
|
216 iListBox->CreateScrollBarFrameL(ETrue); |
|
217 iListBox->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOn, CEikScrollBarFrame::EAuto); |
|
218 |
|
219 SetupListBoxIconsL(); |
|
220 // add list items |
|
221 for(TInt i=0; i<iStoryArray->Count(); i++) |
|
222 { |
|
223 HBufC* story = HBufC::NewLC(KStringHeader().Length() |
|
224 + (*iStoryArray)[i]->Title().Length() |
|
225 + (*iStoryArray)[i]->Teaser().Length() |
|
226 ); |
|
227 TPtr storyPtr = story->Des(); |
|
228 CreateListBoxItemL(storyPtr, TInt(0), (*iStoryArray)[i]->Title(), (*iStoryArray)[i]->Teaser()); |
|
229 AddListBoxItemL(iListBox, storyPtr); |
|
230 CleanupStack::PopAndDestroy(story); |
|
231 } |
|
232 |
|
233 iListBox->SetFocus( ETrue ); |
|
234 iFocusControl = iListBox; |
|
235 } |
|
236 |
|
237 /** |
|
238 * Handle global resource changes, such as scalable UI or skin events (override) |
|
239 */ |
|
240 void CNPRStoryListBox::HandleResourceChange( TInt aType ) |
|
241 { |
|
242 CCoeControl::HandleResourceChange( aType ); |
|
243 SetRect( iAvkonViewAppUi->View( TUid::Uid( ENPRStoryListBoxViewId ) )->ClientRect() ); |
|
244 } |
|
245 |
|
246 /** |
|
247 * Draw container contents. |
|
248 */ |
|
249 void CNPRStoryListBox::Draw( const TRect& aRect ) const |
|
250 { |
|
251 CWindowGc& gc = SystemGc(); |
|
252 gc.Clear( aRect ); |
|
253 } |
|
254 |
|
255 /** |
|
256 * Add a list box item to a list. |
|
257 */ |
|
258 void CNPRStoryListBox::AddListBoxItemL( |
|
259 CEikTextListBox* aListBox, |
|
260 const TDesC& aString ) |
|
261 { |
|
262 CTextListBoxModel* model = aListBox->Model(); |
|
263 CDesCArray* itemArray = static_cast< CDesCArray* > ( model->ItemTextArray() ); |
|
264 itemArray->AppendL( aString ); |
|
265 aListBox->HandleItemAdditionL(); |
|
266 } |
|
267 |
|
268 /** |
|
269 * Get the array of selected item indices, with respect to the list model. |
|
270 * The array is sorted in ascending order. |
|
271 * The array should be destroyed with two calls to CleanupStack::PopAndDestroy(), |
|
272 * the first with no argument (referring to the internal resource) and the |
|
273 * second with the array pointer. |
|
274 * @return newly allocated array, which is left on the cleanup stack; |
|
275 * or NULL for empty list. |
|
276 */ |
|
277 RArray< TInt >* CNPRStoryListBox::GetSelectedListBoxItemsLC( CEikTextListBox* aListBox ) |
|
278 { |
|
279 CAknFilteredTextListBoxModel* model = |
|
280 static_cast< CAknFilteredTextListBoxModel *> ( aListBox->Model() ); |
|
281 if ( model->NumberOfItems() == 0 ) |
|
282 return NULL; |
|
283 |
|
284 // get currently selected indices |
|
285 const CListBoxView::CSelectionIndexArray* selectionIndexes = |
|
286 aListBox->SelectionIndexes(); |
|
287 TInt selectedIndexesCount = selectionIndexes->Count(); |
|
288 if ( selectedIndexesCount == 0 ) |
|
289 return NULL; |
|
290 |
|
291 // copy the indices and sort numerically |
|
292 RArray<TInt>* orderedSelectedIndices = |
|
293 new (ELeave) RArray< TInt >( selectedIndexesCount ); |
|
294 |
|
295 // push the allocated array |
|
296 CleanupStack::PushL( orderedSelectedIndices ); |
|
297 |
|
298 // dispose the array resource |
|
299 CleanupClosePushL( *orderedSelectedIndices ); |
|
300 |
|
301 // see if the search field is enabled |
|
302 CAknListBoxFilterItems* filter = model->Filter(); |
|
303 if ( filter != NULL ) |
|
304 { |
|
305 // when filtering enabled, translate indices back to underlying model |
|
306 for ( TInt idx = 0; idx < selectedIndexesCount; idx++ ) |
|
307 { |
|
308 TInt filteredItem = ( *selectionIndexes ) [ idx ]; |
|
309 TInt actualItem = filter->FilteredItemIndex ( filteredItem ); |
|
310 orderedSelectedIndices->InsertInOrder( actualItem ); |
|
311 } |
|
312 } |
|
313 else |
|
314 { |
|
315 // the selection indices refer directly to the model |
|
316 for ( TInt idx = 0; idx < selectedIndexesCount; idx++ ) |
|
317 orderedSelectedIndices->InsertInOrder( ( *selectionIndexes ) [ idx ] ); |
|
318 } |
|
319 |
|
320 return orderedSelectedIndices; |
|
321 } |
|
322 |
|
323 /** |
|
324 * Delete the selected item or items from the list box. |
|
325 */ |
|
326 void CNPRStoryListBox::DeleteSelectedListBoxItemsL( CEikTextListBox* aListBox ) |
|
327 { |
|
328 CAknFilteredTextListBoxModel* model = |
|
329 static_cast< CAknFilteredTextListBoxModel *> ( aListBox->Model() ); |
|
330 if ( model->NumberOfItems() == 0 ) |
|
331 return; |
|
332 |
|
333 RArray< TInt >* orderedSelectedIndices = GetSelectedListBoxItemsLC( aListBox ); |
|
334 if ( !orderedSelectedIndices ) |
|
335 return; |
|
336 |
|
337 // Delete selected items from bottom up so indices don't change on us |
|
338 CDesCArray* itemArray = static_cast< CDesCArray* > ( model->ItemTextArray() ); |
|
339 TInt currentItem = 0; |
|
340 |
|
341 for ( TInt idx = orderedSelectedIndices->Count(); idx-- > 0; ) |
|
342 { |
|
343 currentItem = ( *orderedSelectedIndices )[ idx ]; |
|
344 itemArray->Delete ( currentItem ); |
|
345 } |
|
346 |
|
347 // dispose the array resources |
|
348 CleanupStack::PopAndDestroy(); |
|
349 |
|
350 // dispose the array pointer |
|
351 CleanupStack::PopAndDestroy( orderedSelectedIndices ); |
|
352 |
|
353 // refresh listbox's cursor now that items are deleted |
|
354 AknListBoxUtils::HandleItemRemovalAndPositionHighlightL( |
|
355 aListBox, currentItem, ETrue ); |
|
356 } |
|
357 |
|
358 /** |
|
359 * Get the listbox. |
|
360 */ |
|
361 CAknDoubleLargeStyleListBox* CNPRStoryListBox::ListBox() |
|
362 { |
|
363 return iListBox; |
|
364 } |
|
365 |
|
366 /** |
|
367 * Create a list box item with the given column values. |
|
368 */ |
|
369 void CNPRStoryListBox::CreateListBoxItemL( TDes& aBuffer, |
|
370 TInt aIconIndex, |
|
371 const TDesC& aMainText, |
|
372 const TDesC& aSecondaryText ) |
|
373 { |
|
374 |
|
375 aBuffer.Format( KStringHeader(), aIconIndex, &aMainText, &aSecondaryText); |
|
376 } |
|
377 |
|
378 /** |
|
379 * Add an item to the list by reading the text items from the array resource |
|
380 * and setting a single image property (if available) from an index |
|
381 * in the list box's icon array. |
|
382 * @param aResourceId id of an ARRAY resource containing the textual |
|
383 * items in the columns |
|
384 * @param aIconIndex the index in the icon array, or -1 |
|
385 */ |
|
386 void CNPRStoryListBox::AddListBoxResourceArrayItemL( TInt aResourceId, TInt aIconIndex ) |
|
387 { |
|
388 CDesCArray* array = iCoeEnv->ReadDesCArrayResourceL( aResourceId ); |
|
389 CleanupStack::PushL( array ); |
|
390 // This is intended to be large enough, but if you get |
|
391 // a USER 11 panic, consider reducing string sizes. |
|
392 TBuf<512> listString; |
|
393 CreateListBoxItemL( listString, aIconIndex, (*array) [0], (*array )[1]); |
|
394 AddListBoxItemL( iListBox, listString ); |
|
395 CleanupStack::PopAndDestroy( array ); |
|
396 } |
|
397 |
|
398 /** |
|
399 * Set up the list's icon array. |
|
400 */ |
|
401 void CNPRStoryListBox::SetupListBoxIconsL() |
|
402 { |
|
403 CArrayPtr< CGulIcon >* icons = new (ELeave) CAknIconArray( 1 ); |
|
404 CleanupStack::PushL( icons ); |
|
405 |
|
406 icons->AppendL(LoadAndScaleIconL(KTestUiFile, |
|
407 EMbmList_iconsNpr_symbian_generic, |
|
408 EMbmList_iconsNpr_symbian_generic_mask, |
|
409 NULL, EAspectRatioPreserved )); |
|
410 |
|
411 CleanupStack::Pop( icons ); |
|
412 |
|
413 if ( icons != NULL ) |
|
414 { |
|
415 iListBox->ItemDrawer()->ColumnData()->SetIconArray( icons ); |
|
416 } |
|
417 } |
|
418 |
|
419 /** |
|
420 * Handle commands relating to markable lists. |
|
421 */ |
|
422 TBool CNPRStoryListBox::HandleMarkableListCommandL(TInt /*aCommand*/) |
|
423 { |
|
424 return EFalse; |
|
425 } |
|
426 |
|
427 /** |
|
428 * This routine loads and scales a bitmap or icon. |
|
429 * |
|
430 * @param aFileName the MBM or MIF filename |
|
431 * @param aBitmapId the bitmap id |
|
432 * @param aMaskId the mask id or -1 for none |
|
433 * @param aSize the TSize for the icon, or NULL to use real size |
|
434 * @param aScaleMode one of the EAspectRatio* enums when scaling |
|
435 * |
|
436 */ |
|
437 CGulIcon* CNPRStoryListBox::LoadAndScaleIconL( |
|
438 const TDesC& aFileName, |
|
439 TInt aBitmapId, |
|
440 TInt aMaskId, |
|
441 TSize* aSize, |
|
442 TScaleMode aScaleMode ) |
|
443 { |
|
444 CFbsBitmap* bitmap; |
|
445 CFbsBitmap* mask; |
|
446 TRAPD(err, AknIconUtils::CreateIconL( bitmap, mask, aFileName, aBitmapId, aMaskId )); |
|
447 |
|
448 TSize size; |
|
449 if ( aSize == NULL ) |
|
450 { |
|
451 // Use size from the image header. In case of SVG, |
|
452 // we preserve the image data for a while longer, since ordinarily |
|
453 // it is disposed at the first GetContentDimensions() or SetSize() call. |
|
454 AknIconUtils::PreserveIconData( bitmap ); |
|
455 AknIconUtils::GetContentDimensions( bitmap, size ); |
|
456 } |
|
457 else |
|
458 { |
|
459 size = *aSize; |
|
460 } |
|
461 |
|
462 AknIconUtils::SetSize( bitmap, size, aScaleMode ); |
|
463 AknIconUtils::SetSize( mask, size, aScaleMode ); |
|
464 |
|
465 if ( aSize == NULL ) |
|
466 { |
|
467 AknIconUtils::DestroyIconData( bitmap ); |
|
468 } |
|
469 |
|
470 return CGulIcon::NewL( bitmap, mask ); |
|
471 } |
|
472 |
|
473 TInt CNPRStoryListBox::CurrentItemIndex() |
|
474 { |
|
475 return iListBox->CurrentItemIndex(); |
|
476 } |
|
477 |
|
478 void CNPRStoryListBox::ShowSelectedStoryL() |
|
479 { |
|
480 // TInt index = CurrentItemIndex(); |
|
481 // static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())-> |
|
482 // ActivateLocalViewL(TUid::Uid(ENPRStoryViewerContainerViewId), TUid::Uid(index),KNullDesC8);//TO DO use custum message instead of custum command |
|
483 |
|
484 TInt currentItem = iListBox->CurrentItemIndex(); |
|
485 if (currentItem==-1) |
|
486 { |
|
487 return; |
|
488 } |
|
489 |
|
490 CNPRStory* story=(*iStoryArray)[currentItem]; |
|
491 |
|
492 //TODO - Move this code into the browser container, so it is seperate from the listbox |
|
493 iHtmlCreator->CreateHtmlFileL(story); |
|
494 |
|
495 static_cast<CNPRAppUi*>(CEikonEnv::Static()->EikAppUi())->ActivateLocalViewL(TUid::Uid(ENPRBrowserViewId)); |
|
496 } |