|
1 /* |
|
2 * Copyright (c) 2002-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: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "AknPhedModel.h" |
|
19 #include "NumberGrouping.h" |
|
20 |
|
21 #include <e32svr.h> |
|
22 #include <AknUtils.h> |
|
23 |
|
24 const TInt KExtraSpaceForGroupedNumber = 6; |
|
25 |
|
26 // |
|
27 // CAknPhedBuffer |
|
28 // |
|
29 CAknPhedScratchBuffer::CAknPhedScratchBuffer() :iPtr(0,0) |
|
30 { |
|
31 } |
|
32 |
|
33 CAknPhedScratchBuffer::~CAknPhedScratchBuffer() |
|
34 { |
|
35 delete iBuf; |
|
36 } |
|
37 |
|
38 void CAknPhedScratchBuffer::ConstructL(TInt aMaxLen) |
|
39 { |
|
40 iBuf = HBufC::NewL(aMaxLen + KExtraSpaceForGroupedNumber); |
|
41 iPtr.Set(iBuf->Des()); |
|
42 } |
|
43 |
|
44 |
|
45 |
|
46 // |
|
47 // CAknPhedModel |
|
48 // |
|
49 CAknPhedModel* CAknPhedModel::NewL( TInt aMaxLen ) |
|
50 { |
|
51 CAknPhedModel* self = new( ELeave ) CAknPhedModel; |
|
52 CleanupStack::PushL( self ); |
|
53 self->ConstructL( aMaxLen ); |
|
54 CleanupStack::Pop( self ); |
|
55 return self; |
|
56 } |
|
57 |
|
58 CAknPhedModel::~CAknPhedModel() |
|
59 { |
|
60 delete iNumberGroupingBuffer; |
|
61 delete iBuf; |
|
62 } |
|
63 |
|
64 void CAknPhedModel::SetText( const TDesC& aText ) |
|
65 { |
|
66 StartEvent(); |
|
67 |
|
68 // delete all existing text |
|
69 TInt len = iRealLength; |
|
70 DeleteLeft( len, len ); |
|
71 |
|
72 // insert the new text |
|
73 SetRealCursorPosition( 0 ); |
|
74 Insert( aText ); |
|
75 |
|
76 ReportEvent(MPhedDataObserver::TAknPhedDataEvent( |
|
77 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
78 0, |
|
79 iNumberGroupingBuffer->Length() ) ); |
|
80 } |
|
81 |
|
82 void CAknPhedModel::Insert( TText aChar ) |
|
83 { |
|
84 StartEvent(); |
|
85 ClearAnySelection(); |
|
86 |
|
87 TInt nOldCursorPos = CursorPosition(); |
|
88 |
|
89 // buffer full rule: Text overflows off the left hand side of the buffer |
|
90 TInt maxLength = MaxDisplayLength(); |
|
91 if ( iRealLength == maxLength ) |
|
92 { |
|
93 if (nOldCursorPos == 0) |
|
94 { |
|
95 ReportEvent( MPhedDataObserver::TAknPhedDataEvent() ); |
|
96 return; |
|
97 } |
|
98 else |
|
99 { |
|
100 DeleteLeft( 1 ); |
|
101 SetRealCursorPosition( iRealCursor - 1 ); |
|
102 } |
|
103 } |
|
104 |
|
105 iNumberGroupingBuffer->Insert( iRealCursor, aChar ); |
|
106 ++iRealLength; |
|
107 iNumberGroupingBuffer->FormattedNumber(); |
|
108 SetRealCursorPosition( iRealCursor + 1 ); |
|
109 if ( Length() > maxLength ) |
|
110 { |
|
111 DeleteLeft( 1 ); |
|
112 SetRealCursorPosition( iRealCursor - 1 ); |
|
113 ReportEvent(MPhedDataObserver::TAknPhedDataEvent( |
|
114 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
115 CursorPosition(), |
|
116 CursorPosition() ) ); |
|
117 } |
|
118 else |
|
119 { |
|
120 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
121 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
122 nOldCursorPos, |
|
123 CursorPosition() ) ); |
|
124 } |
|
125 |
|
126 } |
|
127 |
|
128 void CAknPhedModel::DeleteLeft() |
|
129 { |
|
130 if( !ClearAnySelection() && iRealCursor > 0 ) |
|
131 { |
|
132 StartEvent(); |
|
133 |
|
134 TInt nOldCursorPos = CursorPosition(); |
|
135 |
|
136 DeleteLeft(iRealCursor); |
|
137 |
|
138 SetRealCursorPosition( iRealCursor - 1 ); |
|
139 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
140 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
141 CursorPosition(), |
|
142 CursorPosition() ) ); |
|
143 } |
|
144 |
|
145 } |
|
146 |
|
147 void CAknPhedModel::DeleteLeft( TInt aIndex, TInt aCount ) |
|
148 { |
|
149 aIndex--; // delete char to the left |
|
150 |
|
151 for ( TInt ii = 0; ii < aCount; ++ii ) |
|
152 { |
|
153 iNumberGroupingBuffer->Delete( aIndex - ii ); |
|
154 --iRealLength; |
|
155 } |
|
156 } |
|
157 |
|
158 TPtrC CAknPhedModel::Selection() const |
|
159 { |
|
160 TInt nFrom = LeftMark(); |
|
161 TInt nTo = nFrom + SelectionWidth(); |
|
162 |
|
163 if(!nTo) nTo = iRealLength; |
|
164 |
|
165 return iNumberGroupingBuffer->Selection( nFrom, nTo ); |
|
166 } |
|
167 |
|
168 void CAknPhedModel::Cut( TDes& aCutText ) |
|
169 { |
|
170 aCutText = Selection(); |
|
171 ClearAnySelection(); |
|
172 } |
|
173 |
|
174 void CAknPhedModel::Copy( TDes& aCopiedText ) const |
|
175 { |
|
176 aCopiedText = Selection(); |
|
177 } |
|
178 |
|
179 void CAknPhedModel::Paste( const TDesC& aText ) |
|
180 { |
|
181 ClearAnySelection(); |
|
182 Insert( aText ); |
|
183 } |
|
184 |
|
185 TInt CAknPhedModel::Language() const |
|
186 { |
|
187 TInt language = iNumberGroupingBuffer->Language(); |
|
188 language &= KAknLanguageMask; |
|
189 TInt forceLanguage = iNumberGroupingBuffer->iForceLanguage; |
|
190 forceLanguage &= KAknLanguageMask; |
|
191 |
|
192 return ( ELangAmerican == language || |
|
193 ELangAmerican == forceLanguage) |
|
194 ? ELangAmerican : ELangTest; |
|
195 } |
|
196 |
|
197 TInt CAknPhedModel::Compensate( TInt aRealPosition ) const |
|
198 { |
|
199 TInt nCompensated = 0; |
|
200 if ( Language() ) |
|
201 { |
|
202 if( iCursorDirection == EUp ) |
|
203 nCompensated = aRealPosition + Spaces( 0, aRealPosition ); |
|
204 else if( iCursorDirection == EDown ) |
|
205 nCompensated = aRealPosition + Spaces( 0, aRealPosition + 1 ); |
|
206 } |
|
207 else |
|
208 { |
|
209 nCompensated = aRealPosition; |
|
210 } |
|
211 return nCompensated; |
|
212 } |
|
213 |
|
214 TInt CAknPhedModel::Uncompensate( TInt aCompensatedPosition ) const |
|
215 { |
|
216 TInt nUncompensated = 0; |
|
217 if ( Language() ) |
|
218 { |
|
219 if( iCursorDirection == EUp ) |
|
220 nUncompensated = aCompensatedPosition - Spaces( aCompensatedPosition - 1 ); |
|
221 else if( iCursorDirection == EDown ) |
|
222 nUncompensated = aCompensatedPosition - Spaces( aCompensatedPosition ); |
|
223 } |
|
224 else |
|
225 { |
|
226 nUncompensated = aCompensatedPosition; |
|
227 } |
|
228 return nUncompensated; |
|
229 } |
|
230 |
|
231 TInt CAknPhedModel::SetRealCursorPosition( TInt aCursorPos ) |
|
232 { |
|
233 StartEvent(); |
|
234 if ( SelectionExists() ) |
|
235 { |
|
236 // selection is lost, so report a selection change event |
|
237 StartEvent(); |
|
238 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
239 MPhedDataObserver::TAknPhedDataEvent::ESelection ) ); |
|
240 } |
|
241 |
|
242 iRealCursor = iRealAnchor = aCursorPos; |
|
243 |
|
244 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
245 MPhedDataObserver::TAknPhedDataEvent::ECursor ) ); |
|
246 |
|
247 return iRealCursor; |
|
248 } |
|
249 |
|
250 TInt CAknPhedModel::SetCompensatedCursorPosition( TInt aCursorPos ) |
|
251 { |
|
252 StartEvent(); |
|
253 if ( SelectionExists() ) |
|
254 { |
|
255 // selection is lost, so report a selection change event |
|
256 StartEvent(); |
|
257 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
258 MPhedDataObserver::TAknPhedDataEvent::ESelection ) ); |
|
259 } |
|
260 |
|
261 iRealCursor = iRealAnchor = Uncompensate( aCursorPos ); |
|
262 |
|
263 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
264 MPhedDataObserver::TAknPhedDataEvent::ECursor ) ); |
|
265 |
|
266 return iRealCursor; |
|
267 } |
|
268 |
|
269 TInt CAknPhedModel::SetAnchorPosition(TInt aAnchorPos) |
|
270 { |
|
271 StartEvent(); |
|
272 |
|
273 iRealAnchor = aAnchorPos; |
|
274 |
|
275 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
276 MPhedDataObserver::TAknPhedDataEvent::ESelection ) ); |
|
277 |
|
278 return iRealAnchor; |
|
279 } |
|
280 |
|
281 |
|
282 TInt CAknPhedModel::CursorLeft() |
|
283 { |
|
284 // cursor rule: cursor left -> left of selection or left with wrap to RHS |
|
285 if ( SelectionExists() ) |
|
286 return SetRealCursorPosition( LeftMark() ); |
|
287 else if (iRealCursor > 0) |
|
288 { |
|
289 return SetRealCursorPosition( iRealCursor - 1 ); |
|
290 } |
|
291 else |
|
292 return SetRealCursorPosition( iRealLength ); |
|
293 } |
|
294 |
|
295 TInt CAknPhedModel::CursorRight() |
|
296 { |
|
297 // cursor rule: cursor right -> right of selection or right with wrap to LHS |
|
298 if ( SelectionExists() ) |
|
299 return SetRealCursorPosition( RightMark() ); |
|
300 else if ( iRealCursor < iRealLength ) |
|
301 return SetRealCursorPosition( iRealCursor + 1 ); |
|
302 else |
|
303 return SetRealCursorPosition( 0 ); |
|
304 } |
|
305 |
|
306 void CAknPhedModel::ConstructL( TInt aMaxLen ) |
|
307 { |
|
308 iBuf = new(ELeave) CAknPhedScratchBuffer; |
|
309 iBuf->ConstructL(aMaxLen); |
|
310 |
|
311 // Construct the number grouping engine with the reversed buffer support turned on |
|
312 iNumberGroupingBuffer = CPNGNumberGrouping::NewL( aMaxLen, ETrue ); |
|
313 |
|
314 iSelection.Set( KNullDesC ); |
|
315 iCursorDirection = EUp; |
|
316 |
|
317 iCount = 0; |
|
318 } |
|
319 |
|
320 void CAknPhedModel::Insert( const TDesC& aText ) |
|
321 { |
|
322 StartEvent(); |
|
323 TInt len = aText.Length(); |
|
324 for ( TInt ii=0; ii<len; ii++ ) |
|
325 { |
|
326 Insert( aText[ii] ); |
|
327 } |
|
328 |
|
329 if ( len && iRealCursor > 0 ) |
|
330 { |
|
331 // report a text event if anything actually got inserted |
|
332 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
333 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
334 Max( 0, CursorPosition() - len ), |
|
335 CursorPosition() ) ); |
|
336 } |
|
337 else |
|
338 { |
|
339 // otherwise report nothing |
|
340 ReportEvent( MPhedDataObserver::TAknPhedDataEvent() ); |
|
341 } |
|
342 } |
|
343 |
|
344 TBool CAknPhedModel::ClearAnySelection() |
|
345 { |
|
346 if ( SelectionExists() ) |
|
347 { |
|
348 StartEvent(); |
|
349 TInt left = LeftMark(); |
|
350 TInt right = RightMark(); |
|
351 |
|
352 DeleteLeft( right, SelectionWidth() ); |
|
353 iNumberGroupingBuffer->FormattedNumber(); |
|
354 |
|
355 SetRealCursorPosition( left ); |
|
356 |
|
357 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
358 MPhedDataObserver::TAknPhedDataEvent::EText, |
|
359 CursorPosition(), |
|
360 left ) ); |
|
361 |
|
362 return ETrue; |
|
363 } |
|
364 return EFalse; |
|
365 } |
|
366 |
|
367 void CAknPhedModel::StartEvent() |
|
368 { |
|
369 // Events can be nested, so that one combined event is reported for each external operation |
|
370 if (iEventDepth == 0) |
|
371 iEvent.Reset(); |
|
372 |
|
373 iEventDepth++; |
|
374 } |
|
375 |
|
376 void CAknPhedModel::ReportEvent( const MPhedDataObserver::TAknPhedDataEvent& aEvent ) |
|
377 { |
|
378 // Combine this event with any other nested event and report the lot if the |
|
379 // nesting is finished |
|
380 iEvent.Add( aEvent ); |
|
381 iEventDepth--; |
|
382 |
|
383 if ( iEventDepth == 0 && iObserver && |
|
384 ( iEvent.TextChanged() || iEvent.CursorChanged() || iEvent.SelectionChanged() ) ) |
|
385 { |
|
386 // safety subtlty: event is reported as the very last thing in case the caller |
|
387 // does something stupid, like leave. |
|
388 iObserver->HandlePhedDataEvent( iEvent, this ); |
|
389 } |
|
390 } |
|
391 |
|
392 void CAknPhedModel::SelectMove( TInt aInc ) |
|
393 { |
|
394 // selection rule: selection cursor wraps LHS <-> RHS |
|
395 iRealCursor = iRealCursor + aInc; |
|
396 |
|
397 if ( iRealCursor < 0 ) |
|
398 iRealCursor = iRealLength; |
|
399 else if ( iRealCursor > iRealLength ) |
|
400 iRealCursor = 0; |
|
401 |
|
402 StartEvent(); |
|
403 ReportEvent( MPhedDataObserver::TAknPhedDataEvent( |
|
404 MPhedDataObserver::TAknPhedDataEvent::ESelection | |
|
405 MPhedDataObserver::TAknPhedDataEvent::ECursor ) ); |
|
406 } |
|
407 |
|
408 TBool CAknPhedModel::CursorPositionIsSpace() |
|
409 { |
|
410 TInt nCursorPosition = CursorPosition(); |
|
411 |
|
412 if( nCursorPosition != Length() ) |
|
413 return iNumberGroupingBuffer->IsSpace( nCursorPosition ); |
|
414 else |
|
415 return EFalse; |
|
416 } |
|
417 |
|
418 TInt CAknPhedModel::Spaces( TInt aFromPos, TInt aToPos ) const |
|
419 { |
|
420 TInt spacesCount = 0; |
|
421 TInt toPos = aToPos; |
|
422 |
|
423 for( TInt i = aFromPos; i <= toPos; ++i ) |
|
424 { |
|
425 if( iNumberGroupingBuffer->IsSpace( i ) ) |
|
426 { |
|
427 ++spacesCount; |
|
428 ++toPos; |
|
429 } |
|
430 } |
|
431 |
|
432 return spacesCount; |
|
433 } |
|
434 |
|
435 TInt CAknPhedModel::Spaces( TInt aToPos ) const |
|
436 { |
|
437 TInt spacesCount = 0; |
|
438 TInt toPos = aToPos; |
|
439 |
|
440 for( TInt i = 0; i <= toPos; ++i ) |
|
441 { |
|
442 if( iNumberGroupingBuffer->IsSpace( i ) ) |
|
443 { |
|
444 ++spacesCount; |
|
445 } |
|
446 } |
|
447 |
|
448 return spacesCount; |
|
449 } |
|
450 // |
|
451 // MPhedDataObserver::TAknPhedDataEvent |
|
452 // |
|
453 void MPhedDataObserver::TAknPhedDataEvent::Add( const TAknPhedDataEvent& aEvent ) |
|
454 { |
|
455 if ( aEvent.TextChanged() ) |
|
456 { |
|
457 if ( TextChanged() ) |
|
458 { |
|
459 if ( iStart > aEvent.iStart ) |
|
460 iStart = aEvent.iStart; |
|
461 if ( iEnd < aEvent.iEnd ) |
|
462 iEnd = aEvent.iEnd; |
|
463 } |
|
464 else |
|
465 { |
|
466 iStart = aEvent.iStart; |
|
467 iEnd = aEvent.iEnd; |
|
468 } |
|
469 } |
|
470 |
|
471 iType |= aEvent.iType; |
|
472 } |
|
473 |
|
474 |
|
475 // |
|
476 // TAknPhedDataMirror |
|
477 // |
|
478 void TAknPhedDataMirror::HandlePhedDataEvent( const TAknPhedDataEvent& aEvent, |
|
479 CAknPhedModel* aPhedData ) |
|
480 { |
|
481 // The mirror reverses event positioning from the model |
|
482 if ( iObserver ) |
|
483 { |
|
484 TInt start; |
|
485 TInt end; |
|
486 aEvent.TextChangeRange( start, end ); |
|
487 TAknPhedDataEvent event( aEvent.Type(), Mirror( end ), Mirror( start ) ); |
|
488 iObserver->HandlePhedDataEvent( event, aPhedData ); |
|
489 } |
|
490 } |
|
491 |
|
492 TInt TAknPhedDataMirror::Compensate( TInt aMirrorPosition ) const |
|
493 { |
|
494 TInt Compensated ; |
|
495 if ( iPhed->Language() ) |
|
496 { |
|
497 Compensated = aMirrorPosition - iPhed->Spaces( 0, iPhed->iRealCursor ); |
|
498 } |
|
499 else |
|
500 { |
|
501 Compensated = aMirrorPosition; |
|
502 } |
|
503 return Compensated; |
|
504 } |
|
505 |
|
506 // End of File |
|
507 |