|
1 /* |
|
2 * Copyright (c) 1997-1999 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 <gdi.h> |
|
20 #include <badesca.h> // CDesArray |
|
21 #include <eiklbed.h> // class CEikListBoxTextEditor header file |
|
22 #include <uikon.hrh> |
|
23 #include <gulutil.h> |
|
24 #include <eikedwin.h> |
|
25 #include <eikenv.h> |
|
26 #include <eikappui.h> |
|
27 #include <txtglobl.h> // CGlobalText |
|
28 #include <txtfmlyr.h> // CParaFormatLayer, CCharFormatLayer |
|
29 #include <eikcoctl.rsg> |
|
30 #include <AknTasHook.h> |
|
31 #include "LAFLBED.H" |
|
32 #include "akntrace.h" |
|
33 enum TTUiklbedPanic |
|
34 { |
|
35 ETUiklbedPanicEndMarkMissing, |
|
36 ETUiklbedPanicEmptyField, |
|
37 ETUiklbedPanicLongInput, |
|
38 }; |
|
39 |
|
40 LOCAL_C void Panic(TTUiklbedPanic aPanic) |
|
41 { |
|
42 _LIT(KTUiklbed,"TUiklbed"); |
|
43 User::Panic(KTUiklbed, aPanic); |
|
44 } |
|
45 |
|
46 // |
|
47 // MEikListBoxEditor |
|
48 // |
|
49 |
|
50 EXPORT_C void MEikListBoxEditor::MEikListBoxEditor_Reserved_1() |
|
51 { |
|
52 } |
|
53 |
|
54 // |
|
55 // CEikListBoxTextEditor |
|
56 // |
|
57 |
|
58 EXPORT_C CEikListBoxTextEditor::CEikListBoxTextEditor( MListBoxModel* aModel ) |
|
59 : iModel(aModel), iEditor(NULL), iFont(NULL), iItemPos(0), iItemLen(0) |
|
60 { |
|
61 _AKNTRACE_FUNC_ENTER; |
|
62 iFont = CONST_CAST(CFont*,CCoeEnv::Static()->NormalFont()); |
|
63 AKNTASHOOK_ADD( this, "CEikListBoxTextEditor" ); |
|
64 _AKNTRACE_FUNC_EXIT; |
|
65 } |
|
66 |
|
67 EXPORT_C CEikListBoxTextEditor::~CEikListBoxTextEditor() |
|
68 { // need to remove from stack incase listbox was destroyed without calling StopEditingL() |
|
69 // safe to call RemoveFromStack even if we're not stacked |
|
70 // code here is same as in StopEditingL(), but we can't call |
|
71 // a L function from ~ even if it can't leave |
|
72 _AKNTRACE_FUNC_ENTER; |
|
73 AKNTASHOOK_REMOVE(); |
|
74 iEikonEnv->EikAppUi()->RemoveFromStack(this); |
|
75 if(iEditor) |
|
76 iEditor->SetFocus(EFalse); // BUG? - cursor remains on screen without this |
|
77 delete iEditor; |
|
78 delete iParaFormatLayer; |
|
79 delete iCharFormatLayer; |
|
80 _AKNTRACE_FUNC_EXIT; |
|
81 } |
|
82 |
|
83 EXPORT_C void CEikListBoxTextEditor::Release() |
|
84 { |
|
85 delete this; |
|
86 } |
|
87 |
|
88 EXPORT_C void CEikListBoxTextEditor::SetFont(const CFont* aFont) |
|
89 { |
|
90 if (aFont!=NULL) |
|
91 iFont = CONST_CAST(CFont*,aFont); |
|
92 } |
|
93 |
|
94 void CEikListBoxTextEditor::UseFontL( CEikEdwin& aEditor, const CFont& aFont ) |
|
95 { |
|
96 _AKNTRACE_FUNC_ENTER; |
|
97 CGlobalText* globalText; |
|
98 |
|
99 TCharFormatMask defaultCharFormatMask; |
|
100 defaultCharFormatMask.SetAttrib(EAttFontTypeface); |
|
101 defaultCharFormatMask.SetAttrib(EAttFontHeight); |
|
102 TFontSpec fontspec = aFont.FontSpecInTwips(); |
|
103 TCharFormat defaultCharFormat( fontspec.iTypeface.iName, fontspec.iHeight ); |
|
104 |
|
105 iParaFormatLayer=CParaFormatLayer::NewL(); |
|
106 iCharFormatLayer=CCharFormatLayer::NewL(defaultCharFormat,defaultCharFormatMask); |
|
107 globalText=CGlobalText::NewL(iParaFormatLayer,iCharFormatLayer,CEditableText::ESegmentedStorage,5); |
|
108 CleanupStack::PushL(globalText); |
|
109 |
|
110 TCharFormat charFormat; |
|
111 TCharFormatMask charMask; |
|
112 iCharFormatLayer->Sense(charFormat,charMask); |
|
113 if ( fontspec.iFontStyle.Posture()==EPostureItalic ) |
|
114 { |
|
115 charMask.SetAttrib(EAttFontPosture); |
|
116 charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic); |
|
117 } |
|
118 if ( fontspec.iFontStyle.StrokeWeight()==EStrokeWeightBold ) |
|
119 { |
|
120 charMask.SetAttrib(EAttFontStrokeWeight ); |
|
121 charFormat.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold); |
|
122 } |
|
123 iCharFormatLayer->SetL(charFormat,charMask); |
|
124 |
|
125 CPlainText* old=aEditor.Text(); |
|
126 CleanupStack::Pop(); // globalText |
|
127 CleanupStack::PushL(old); // old is pushed because we're using EUseText in the subsequent call |
|
128 aEditor.SetDocumentContentL(*globalText,CEikEdwin::EUseText); |
|
129 CleanupStack::PopAndDestroy(); // old |
|
130 _AKNTRACE_FUNC_EXIT; |
|
131 } |
|
132 |
|
133 EXPORT_C CEikEdwin* CEikListBoxTextEditor::Editor() |
|
134 { |
|
135 return iEditor; |
|
136 } |
|
137 |
|
138 EXPORT_C MListBoxModel* CEikListBoxTextEditor::ListBoxModel() |
|
139 { |
|
140 return iModel; |
|
141 } |
|
142 |
|
143 EXPORT_C void CEikListBoxTextEditor::StartEditingL(const CCoeControl& aContainer, const TRect& aRect, TInt aItemIndex, TInt aMaxLength ) |
|
144 { |
|
145 _AKNTRACE_FUNC_ENTER; |
|
146 if (Editor()) |
|
147 { |
|
148 _AKNTRACE_FUNC_EXIT; |
|
149 return; // quit if editing is currently on |
|
150 } |
|
151 |
|
152 iItemIndex=aItemIndex; |
|
153 TRect rect=aRect; |
|
154 TPtrC itemtext=EditableItemText(&rect); // get text (also partly editable) |
|
155 |
|
156 // create edwin (make it into own window, no wrapping) |
|
157 TGulBorder border; |
|
158 LafListBoxTextEditor::GetDefaultBorder(border); |
|
159 CEikEdwin* editor=new(ELeave) CEikEdwin(border); |
|
160 CleanupStack::PushL(editor); |
|
161 TInt edwinFlags=EEikEdwinOwnsWindow | EEikEdwinNoWrap | EEikEdwinNoLineOrParaBreaks | EEikEdwinNoCustomDraw; |
|
162 editor->CEikEdwin::ConstructL(edwinFlags,0,(iItemLen?iItemLen:aMaxLength),1); |
|
163 editor->SetContainerWindowL(aContainer); |
|
164 editor->SetRect(rect); |
|
165 UseFontL(*editor,*iFont); // need this to change CEikEdwin font... |
|
166 editor->SetTextL(&itemtext); |
|
167 editor->SetCursorPosL(editor->TextLength(),ETrue); |
|
168 editor->SetFocus(ETrue); |
|
169 editor->ActivateL(); |
|
170 iEikonEnv->EikAppUi()->AddToStackL(this,ECoeStackPriorityDialog,ECoeStackFlagRefusesFocus); |
|
171 CleanupStack::Pop(); // editor |
|
172 iEditor=editor; |
|
173 iCoeEnv->InputCapabilitiesChanged(); |
|
174 _AKNTRACE_FUNC_EXIT; |
|
175 } |
|
176 |
|
177 /** |
|
178 * Writes the internal state of the control and its components to aStream. |
|
179 * Does nothing in release mode. |
|
180 * Designed to be overidden and base called by subclasses. |
|
181 * |
|
182 * @internal |
|
183 * @since App-Framework_6.1 |
|
184 */ |
|
185 #ifndef _DEBUG |
|
186 EXPORT_C void CEikListBoxTextEditor::WriteInternalStateL(RWriteStream&) const |
|
187 {} |
|
188 #else |
|
189 EXPORT_C void CEikListBoxTextEditor::WriteInternalStateL(RWriteStream& aWriteStream) const |
|
190 { |
|
191 _LIT(KEikLitLbxEdCtlStart,"<CEikListBoxTextEditor>"); |
|
192 _LIT(KEikLitLbxEdCtlEnd,"<\\CEikListBoxTextEditor>"); |
|
193 _LIT(KEikLitLbxEdObs,"<iEditorObserver>"); |
|
194 _LIT(KEikLitLbxEdObsEnd,"<\\iEditorObserver>"); |
|
195 _LIT(KEikLitLbxEdMdl,"<iModel>"); |
|
196 _LIT(KEikLitLbxEdMdlEnd,"<\\iModel>"); |
|
197 _LIT(KEikLitLbxEdEdr,"<iEditor>"); |
|
198 _LIT(KEikLitLbxEdEdrEnd,"<\\iEditor>"); |
|
199 _LIT(KEikLitLbxEdIndx,"<iItemIndex>"); |
|
200 _LIT(KEikLitLbxEdIndxEnd,"<\\iItemIndex>"); |
|
201 _LIT(KEikLitLbxEdFont,"<iFont>"); |
|
202 _LIT(KEikLitLbxEdFontEnd,"<\\iFont>"); |
|
203 _LIT(KEikLitLbxEdItemPos,"<iItemPos>"); |
|
204 _LIT(KEikLitLbxEdItemPosEnd,"<\\iItemPos>"); |
|
205 _LIT(KEikLitLbxEdItemLen,"<iItemLen>"); |
|
206 _LIT(KEikLitLbxEdItemLenEnd,"<\\iItemLen>"); |
|
207 _LIT(KEikLitLbxEdParaLay,"<iParaFormatLayer>"); |
|
208 _LIT(KEikLitLbxEdParaLayEnd,"<\\iParaFormatLayer>"); |
|
209 _LIT(KEikLitLbxEdCharLay,"<iCharFormatLayer>"); |
|
210 _LIT(KEikLitLbxEdCharLayEnd,"<\\iCharFormatLayer>"); |
|
211 |
|
212 aWriteStream << KEikLitLbxEdCtlStart; |
|
213 aWriteStream << KEikLitLbxEdObs; |
|
214 aWriteStream.WriteInt32L((TInt)iEditorObserver); |
|
215 aWriteStream << KEikLitLbxEdObsEnd; |
|
216 aWriteStream << KEikLitLbxEdMdl; |
|
217 aWriteStream.WriteInt32L((TInt)iModel); |
|
218 aWriteStream << KEikLitLbxEdMdlEnd; |
|
219 aWriteStream << KEikLitLbxEdEdr; |
|
220 iEditor->WriteInternalStateL(aWriteStream); // won't be done as a component |
|
221 aWriteStream << KEikLitLbxEdEdrEnd; |
|
222 aWriteStream << KEikLitLbxEdIndx; |
|
223 aWriteStream.WriteInt32L(iItemIndex); |
|
224 aWriteStream << KEikLitLbxEdIndxEnd; |
|
225 aWriteStream << KEikLitLbxEdFont; |
|
226 const TFontSpec& spec=iFont->FontSpecInTwips(); |
|
227 aWriteStream << spec; |
|
228 aWriteStream << KEikLitLbxEdFontEnd; |
|
229 aWriteStream << KEikLitLbxEdItemPos; |
|
230 aWriteStream.WriteInt32L(iItemPos); |
|
231 aWriteStream << KEikLitLbxEdItemPosEnd; |
|
232 aWriteStream << KEikLitLbxEdItemLen; |
|
233 aWriteStream.WriteInt32L(iItemLen); |
|
234 aWriteStream << KEikLitLbxEdItemLenEnd; |
|
235 aWriteStream << KEikLitLbxEdParaLay; |
|
236 aWriteStream << *iParaFormatLayer; |
|
237 aWriteStream << KEikLitLbxEdParaLayEnd; |
|
238 aWriteStream << KEikLitLbxEdCharLay; |
|
239 aWriteStream << *iCharFormatLayer; |
|
240 aWriteStream << KEikLitLbxEdCharLayEnd; |
|
241 CCoeControl::WriteInternalStateL(aWriteStream); |
|
242 aWriteStream << KEikLitLbxEdCtlEnd; |
|
243 } |
|
244 #endif |
|
245 |
|
246 EXPORT_C TPtrC CEikListBoxTextEditor::ItemText() |
|
247 { |
|
248 return static_cast<MTextListBoxModel*>(ListBoxModel())->ItemText(ItemIndex()); |
|
249 } |
|
250 |
|
251 TPtrC CEikListBoxTextEditor::EditableItemText(TRect* aRect) |
|
252 { |
|
253 _AKNTRACE_FUNC_ENTER; |
|
254 TPtrC itemtext = ItemText(); |
|
255 if (iItemPos==0) // not yet set (and even if set, cannot be zero) |
|
256 { |
|
257 iItemPos = itemtext.Locate('\n'); // loacte partly editable item start |
|
258 if (iItemPos != KErrNotFound) |
|
259 { |
|
260 iItemPos++; // jump over mark character |
|
261 iItemLen = itemtext.Mid( iItemPos ).Locate('\n'); // locate string end |
|
262 if ( iItemLen == KErrNotFound ) |
|
263 Panic( ETUiklbedPanicEndMarkMissing ); |
|
264 if ( iItemLen==0 ) |
|
265 Panic( ETUiklbedPanicEmptyField ); |
|
266 TPtrC head = itemtext.Left( iItemPos ); |
|
267 TPtrC body = itemtext.Mid( iItemPos, iItemLen ); |
|
268 if ( aRect ) // adjust the rect if it is given |
|
269 { |
|
270 aRect->iTl.iX += iFont->TextWidthInPixels( head ); |
|
271 aRect->iBr.iX = aRect->iTl.iX + iFont->TextWidthInPixels( body ) + 4; |
|
272 } |
|
273 _AKNTRACE_FUNC_EXIT; |
|
274 return body; |
|
275 } |
|
276 iItemPos = 0; // partly editable text not found |
|
277 } |
|
278 _AKNTRACE_FUNC_EXIT; |
|
279 return itemtext; |
|
280 } |
|
281 |
|
282 EXPORT_C void CEikListBoxTextEditor::HandlePointerEventL(const TPointerEvent& aPointerEvent) |
|
283 { |
|
284 CAknControl::HandlePointerEventL(aPointerEvent); |
|
285 } |
|
286 |
|
287 EXPORT_C void* CEikListBoxTextEditor::ExtensionInterface( TUid /*aInterface*/ ) |
|
288 { |
|
289 return NULL; |
|
290 } |
|
291 |
|
292 /** |
|
293 * Stops editing the current item, if editing was taking place. Does not Leave. |
|
294 * |
|
295 * @since Uikon1.2 |
|
296 */ |
|
297 EXPORT_C void CEikListBoxTextEditor::StopEditingL() |
|
298 { |
|
299 iEikonEnv->EikAppUi()->RemoveFromStack(this); |
|
300 if ( Editor() == NULL ) return; // quit if editing is not currently on |
|
301 iEditor->SetFocus(EFalse); // BUG? - cursor remains on screen without this |
|
302 delete iEditor; |
|
303 iEditor=NULL; |
|
304 iCoeEnv->InputCapabilitiesChanged(); |
|
305 } |
|
306 |
|
307 EXPORT_C TBool CEikListBoxTextEditor::UpdateModelL() |
|
308 // virtual - needs to be rewritten if editing other than single column text list |
|
309 { |
|
310 _AKNTRACE_FUNC_ENTER; |
|
311 if (!Editor()) |
|
312 { |
|
313 _AKNTRACE_FUNC_EXIT; |
|
314 return EFalse; // quit if editing is not currently on |
|
315 } |
|
316 const MDesCArray* matchableTextArray=ListBoxModel()->MatchableTextArray(); |
|
317 CDesCArray* textArray=(CDesCArray*)matchableTextArray; |
|
318 |
|
319 TPtrC itemtext = ItemText(); |
|
320 if ( iItemPos ) // partly editable item? |
|
321 { |
|
322 HBufC* itemBuffer= HBufC::New(itemtext.Length()); |
|
323 CleanupStack::PushL( itemBuffer ); |
|
324 TPtr itemPointer = itemBuffer->Des(); |
|
325 |
|
326 itemPointer.Append( itemtext.Left( iItemPos ) ); |
|
327 |
|
328 HBufC* ptr=iEditor->GetTextInHBufL(); |
|
329 TPtrC newText; |
|
330 if (ptr) |
|
331 { |
|
332 newText.Set(ptr->Des()); |
|
333 } |
|
334 TInt addSpaces = iItemLen - newText.Length(); |
|
335 for (TInt index=0; ((addSpaces>0) && (index<addSpaces)); index++) |
|
336 itemPointer.Append(_L(" ")); |
|
337 |
|
338 itemPointer.Append( newText ); |
|
339 itemPointer.Append( itemtext.Right( itemtext.Length()-iItemPos-iItemLen ) ); |
|
340 |
|
341 delete ptr; |
|
342 textArray->InsertL( ItemIndex(), *itemBuffer ); |
|
343 CleanupStack::PopAndDestroy(); // itemBuffer |
|
344 |
|
345 textArray->Delete( ItemIndex()+1 ); |
|
346 } |
|
347 else // replace the whole list item |
|
348 { |
|
349 HBufC* newText = iEditor->GetTextInHBufL(); |
|
350 if (!newText) return ETrue; // if user tries to insert an empty text... |
|
351 |
|
352 CleanupStack::PushL(newText); |
|
353 textArray->InsertL(ItemIndex(),*newText); |
|
354 CleanupStack::PopAndDestroy(); // newText |
|
355 |
|
356 textArray->Delete( ItemIndex() + 1 ); |
|
357 } |
|
358 _AKNTRACE_FUNC_EXIT; |
|
359 return ETrue; |
|
360 } |
|
361 |
|
362 EXPORT_C TInt CEikListBoxTextEditor::ItemIndex() const |
|
363 { |
|
364 return iItemIndex; |
|
365 } |
|
366 |
|
367 EXPORT_C TKeyResponse CEikListBoxTextEditor::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) |
|
368 { |
|
369 _AKNTRACE_FUNC_ENTER; |
|
370 _AKNTRACE( "aKeyEvent.iCode is %d", aKeyEvent.iCode ); |
|
371 _AKNTRACE( "aKeyEvent.iScanCode is %d", aKeyEvent.iScanCode ); |
|
372 _AKNTRACE( "aType is %d", aType ); |
|
373 if (!Editor() || aType!=EEventKey) |
|
374 { |
|
375 _AKNTRACE_FUNC_EXIT; |
|
376 return EKeyWasNotConsumed; |
|
377 } |
|
378 |
|
379 if(iEditorObserver && iEditorObserver->HandleListBoxEditorEventL(this,aKeyEvent)==EKeyWasConsumed) |
|
380 { // gives owning dialogs or listboxes a chance to intecept keys prior to or instead of passing to editor |
|
381 // eg the CCknFileSaveAsDialog needs to check if a file exists when the enter key is pressed |
|
382 // and prevent the Enter key being passed on to the editor, or intecept the up/down keys to |
|
383 // allow scrolling out of the editor |
|
384 _AKNTRACE_FUNC_EXIT; |
|
385 return EKeyWasConsumed; |
|
386 } |
|
387 const TInt code=aKeyEvent.iCode; |
|
388 if (aKeyEvent.iModifiers&(EModifierCtrl|EModifierShift)==(EModifierCtrl|EModifierShift)) |
|
389 { |
|
390 TBuf<24> buf; |
|
391 iCoeEnv->ReadResource(buf,R_EIK_EDWIN_SHIFT_CTRL_HOTKEYS); |
|
392 const TInt pos=buf.Locate(TChar(code+'a'-1)); |
|
393 if (pos==CEikEdwin::EHotKeyInsertChar) |
|
394 { |
|
395 _AKNTRACE_FUNC_EXIT; |
|
396 return EKeyWasConsumed; |
|
397 } |
|
398 } |
|
399 switch (code) |
|
400 { |
|
401 case EKeyEnter: // stop editing and update data |
|
402 case EKeyOK: |
|
403 UpdateModelL(); |
|
404 StopEditingL(); |
|
405 break; |
|
406 case EKeyEscape: // stop editing and don't update data |
|
407 StopEditingL(); |
|
408 break; |
|
409 default: |
|
410 Editor()->OfferKeyEventL(aKeyEvent,aType); |
|
411 } |
|
412 _AKNTRACE_FUNC_EXIT; |
|
413 return EKeyWasConsumed; |
|
414 } |
|
415 |
|
416 EXPORT_C void CEikListBoxTextEditor::SetListBoxEditorObserver(MListBoxEditorObserver* aObserver) |
|
417 { |
|
418 iEditorObserver=aObserver; |
|
419 } |
|
420 |
|
421 EXPORT_C void CEikListBoxTextEditor::MEikListBoxEditor_Reserved_1() |
|
422 { |
|
423 } |