landmarksui/uicontrols/src/CLmkMfneFloat.cpp
branchRCL_3
changeset 17 1fc85118c3ae
parent 16 8173571d354e
child 18 870918037e16
equal deleted inserted replaced
16:8173571d354e 17:1fc85118c3ae
     1 /*
       
     2 * Copyright (c) 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:    LandmarksUi Content File -
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 
       
    22 
       
    23 
       
    24 
       
    25 // INCLUDE FILES
       
    26 #include <e32math.h>
       
    27 #include "CLmkMfneFloat.h"
       
    28 #include <aknutils.h>
       
    29 
       
    30 namespace {
       
    31 
       
    32 const TInt KNumOtherSymbols = 2; // +/- and decimal point
       
    33 
       
    34 _LIT(KMinus,"-");
       
    35 
       
    36 const TInt KEventCodeStarSign(42);
       
    37 const TInt KEventCodeMinusSign(45);
       
    38 const TInt KKeyToMatchPoint = 35; // Shift/Hash
       
    39 const TInt KPointKeyFromQwerty = 46;
       
    40 
       
    41 #if defined(_DEBUG)
       
    42 void Panic(TInt aReason)
       
    43     {
       
    44     _LIT(KPanicCategory, "LMK_MFNE_FLT");
       
    45     User::Panic(KPanicCategory, aReason);
       
    46     }
       
    47 #endif
       
    48 
       
    49 TReal Nan()
       
    50     {
       
    51     TRealX nan;
       
    52     nan.SetNaN();
       
    53     return nan;
       
    54     }
       
    55 
       
    56 TBool IsAnyDigit(TChar aCharacter)
       
    57 	{
       
    58 	return (aCharacter.GetNumericValue() != KErrNotFound);
       
    59 	}
       
    60 
       
    61 void TrimRightmostChar(TDes& aText)
       
    62     {
       
    63     if (aText.Length())
       
    64         {
       
    65         aText.SetLength(aText.Length() - 1);
       
    66         }
       
    67     }
       
    68 }
       
    69 
       
    70 // ---------------------------------------------------------
       
    71 // CLmkMfneFloat::CLmkMfneFloat
       
    72 // ---------------------------------------------------------
       
    73 //
       
    74 CLmkMfneFloat::CLmkMfneFloat(
       
    75     TInt aMaxDigits,
       
    76     TInt aMaxDecimalDigits)
       
    77     :
       
    78     iMaxDigits(aMaxDigits),
       
    79     iMaxDecimalDigits(aMaxDecimalDigits)
       
    80     {
       
    81     __ASSERT_DEBUG(aMaxDigits > 0, Panic(KErrArgument));
       
    82     __ASSERT_DEBUG(aMaxDecimalDigits > 0, Panic(KErrArgument));
       
    83     __ASSERT_DEBUG(aMaxDecimalDigits <= aMaxDigits, Panic(KErrArgument));
       
    84     }
       
    85 
       
    86 // ---------------------------------------------------------
       
    87 // CLmkMfneFloat::~CLmkMfneFloat
       
    88 // ---------------------------------------------------------
       
    89 //
       
    90 CLmkMfneFloat::~CLmkMfneFloat()
       
    91     {
       
    92     delete iText;
       
    93     }
       
    94 
       
    95 // ---------------------------------------------------------
       
    96 // CLmkMfneFloat::NewL
       
    97 // ---------------------------------------------------------
       
    98 //
       
    99 CLmkMfneFloat* CLmkMfneFloat::NewL(
       
   100     TInt aMaxDigits,
       
   101     TInt aMaxDecimalDigits)
       
   102     {
       
   103     CLmkMfneFloat* number = new(ELeave)
       
   104         CLmkMfneFloat(aMaxDigits, aMaxDecimalDigits);
       
   105 
       
   106     CleanupStack::PushL(number);
       
   107     number->ConstructL();
       
   108     CleanupStack::Pop();
       
   109 
       
   110     return number;
       
   111     }
       
   112 
       
   113 // ---------------------------------------------------------
       
   114 // CLmkMfneFloat::ConstructL
       
   115 // ---------------------------------------------------------
       
   116 //
       
   117 void CLmkMfneFloat::ConstructL()
       
   118     {
       
   119     iText = HBufC::NewL(MaxNumOfChars());
       
   120     }
       
   121 
       
   122 // ---------------------------------------------------------
       
   123 // CLmkMfneFloat::SetLimits
       
   124 // ---------------------------------------------------------
       
   125 //
       
   126 TBool CLmkMfneFloat::SetLimits(
       
   127     TReal aMinimumValue,
       
   128     TReal aMaximumValue)
       
   129     {
       
   130     __ASSERT_DEBUG(
       
   131         Math::IsNaN(aMinimumValue) ||
       
   132         Math::IsNaN(aMaximumValue) ||
       
   133         (aMinimumValue < aMaximumValue), Panic(KErrArgument));
       
   134 
       
   135     iMinimumValue = aMinimumValue;
       
   136     iMaximumValue = aMaximumValue;
       
   137 
       
   138     return EnsureValueInLimits(ValueFromText(*iText));
       
   139     }
       
   140 
       
   141 // ---------------------------------------------------------
       
   142 // CLmkMfneFloat::GetLimits
       
   143 // ---------------------------------------------------------
       
   144 //
       
   145 void CLmkMfneFloat::GetLimits(
       
   146     TReal& aMinimumValue,
       
   147     TReal& aMaximumValue) const
       
   148     {
       
   149     aMinimumValue = iMinimumValue;
       
   150     aMaximumValue = iMaximumValue;
       
   151     }
       
   152 
       
   153 // ---------------------------------------------------------
       
   154 // CLmkMfneFloat::SetValue
       
   155 // ---------------------------------------------------------
       
   156 //
       
   157 void CLmkMfneFloat::SetValue(TReal aValue)
       
   158     {
       
   159     TPtr ptr(iText->Des());
       
   160     TextFromValue(aValue, ptr);
       
   161     AknTextUtils::DisplayTextLanguageSpecificNumberConversion( ptr );
       
   162     EnsureValueInLimits(aValue);
       
   163     iIsBeingEditedWithCursor = EFalse;
       
   164     }
       
   165 
       
   166 // ---------------------------------------------------------
       
   167 // CLmkMfneFloat::Value
       
   168 // ---------------------------------------------------------
       
   169 //
       
   170 TReal CLmkMfneFloat::Value() const
       
   171     {
       
   172     return ValueFromText(*iText);
       
   173     }
       
   174 
       
   175 // ---------------------------------------------------------
       
   176 // CLmkMfneFloat::MaximumWidthInPixels
       
   177 // ---------------------------------------------------------
       
   178 //
       
   179 TInt CLmkMfneFloat::MaximumWidthInPixels(
       
   180     const CFont& aFont,
       
   181     TBool /*aShrinkToMinimumSize*/)
       
   182     {
       
   183     TLocale locale;
       
   184     TInt digitWidth =
       
   185         TFindWidthOfWidestDigitType(locale.DigitType()).MaximumWidthInPixels(aFont);
       
   186 
       
   187     return MaxNumOfChars() * digitWidth;
       
   188     }
       
   189 
       
   190 // ---------------------------------------------------------
       
   191 // CLmkMfneFloat::InputCapabilities
       
   192 // ---------------------------------------------------------
       
   193 //
       
   194 TCoeInputCapabilities CLmkMfneFloat::InputCapabilities() const
       
   195     {
       
   196     return TCoeInputCapabilities(TCoeInputCapabilities::EWesternNumericReal);
       
   197     }
       
   198 
       
   199 // ---------------------------------------------------------
       
   200 // CLmkMfneFloat::IsEditable
       
   201 // ---------------------------------------------------------
       
   202 //
       
   203 TBool CLmkMfneFloat::IsEditable() const
       
   204     {
       
   205     return ETrue;
       
   206     }
       
   207 
       
   208 // ---------------------------------------------------------
       
   209 // CLmkMfneFloat::HandleHighlight
       
   210 // ---------------------------------------------------------
       
   211 //
       
   212 void CLmkMfneFloat::HandleHighlight()
       
   213     {
       
   214     iFocus = ETrue;
       
   215     if ((iText->Length() == 0))
       
   216         {
       
   217         iIsBeingEditedWithCursor = ETrue;
       
   218         }
       
   219     }
       
   220 
       
   221 // ---------------------------------------------------------
       
   222 // CLmkMfneFloat::HighlightType
       
   223 // ---------------------------------------------------------
       
   224 //
       
   225 CEikMfneField::THighlightType CLmkMfneFloat::HighlightType() const
       
   226     {
       
   227     if (iFocus)
       
   228         {
       
   229         return iIsBeingEditedWithCursor ? ECursor : EInverseVideo;
       
   230         }
       
   231     else
       
   232         {
       
   233         return EInverseVideo;
       
   234         }
       
   235     }
       
   236 
       
   237 // ---------------------------------------------------------
       
   238 // CLmkMfneFloat::HandleDeHighlight
       
   239 // ---------------------------------------------------------
       
   240 //
       
   241 void CLmkMfneFloat::HandleDeHighlight(
       
   242     const CFont& /*aFont*/,
       
   243     CEikonEnv& /*aEikonEnv*/,
       
   244     TBool& aDataAltered,
       
   245     TBool& /*aError*/)
       
   246     {
       
   247     iIsBeingEditedWithCursor = EFalse;
       
   248     iFocus = EFalse;
       
   249 
       
   250     TPtr text(iText->Des());
       
   251     if (Math::IsNaN(ValueFromText(text)))
       
   252         {
       
   253         text.Zero();
       
   254         aDataAltered = ETrue;
       
   255         }
       
   256     }
       
   257 
       
   258 // ---------------------------------------------------------
       
   259 // CLmkMfneFloat::HandleKey
       
   260 // ---------------------------------------------------------
       
   261 //
       
   262 void CLmkMfneFloat::HandleKey(
       
   263     const CFont& /*aFont*/,
       
   264     const TKeyEvent& aKeyEvent,
       
   265     TBool /*aInterpretLeftAndRightAsEarEvents*/,
       
   266     TBool& aDataAltered,
       
   267     TInt& aHighlightIncrement)
       
   268     {
       
   269     TChar ch = aKeyEvent.iCode;
       
   270     TPtr text = iText->Des();
       
   271 
       
   272     switch (ch)
       
   273         {
       
   274         case EKeyLeftArrow:
       
   275         case EKeyRightArrow:
       
   276             HandleLeftOrRightArrow(ch, aDataAltered, aHighlightIncrement);
       
   277             break;
       
   278 
       
   279         case EKeyBackspace:
       
   280             if (text.Length())
       
   281                 {
       
   282                 iIsBeingEditedWithCursor = ETrue;
       
   283                 TrimRightmostChar(text);
       
   284                 if (text == KMinus)
       
   285                     {
       
   286                     text.Zero();
       
   287                     }
       
   288                 aDataAltered=ETrue;
       
   289                 }
       
   290             break;
       
   291 
       
   292         case KEventCodeStarSign:
       
   293         case KEventCodeMinusSign:
       
   294             // if negative values allowed
       
   295             if (Math::IsNaN(iMinimumValue) || iMinimumValue < 0)
       
   296                 {
       
   297                 if (!iIsBeingEditedWithCursor)
       
   298                     {
       
   299                     iIsBeingEditedWithCursor = ETrue;
       
   300                     text.Zero();
       
   301                     }
       
   302 
       
   303                 if (text.Length() == 0)
       
   304                     {
       
   305                     text.Append(KMinus);
       
   306                     aDataAltered=ETrue;
       
   307                     }
       
   308                 }
       
   309             break;
       
   310 
       
   311         default:
       
   312             TLocale locale;
       
   313             TChar point = locale.DecimalSeparator();
       
   314 
       
   315             if ((ch == KKeyToMatchPoint || ch == KPointKeyFromQwerty ) && (iIsBeingEditedWithCursor))
       
   316                 {
       
   317                 if (IsDecimalSeparatorAllowed(text))
       
   318                     {
       
   319                     text.Append(point);
       
   320                     aDataAltered = ETrue;
       
   321                     }
       
   322                 }
       
   323 
       
   324             if (IsAnyDigit(ch))
       
   325                 {
       
   326                 if (!iIsBeingEditedWithCursor)
       
   327                     {
       
   328                     iIsBeingEditedWithCursor = ETrue;
       
   329                     text.Zero();
       
   330                     aDataAltered=ETrue;
       
   331                     }
       
   332 
       
   333                 if (IsMoreDigitsAllowed(text))
       
   334                     {
       
   335                     text.Append(ch);
       
   336                     aDataAltered = ETrue;
       
   337 
       
   338                     // check that value is within limits
       
   339                     if (EnsureValueInLimits(ValueFromText(text)))
       
   340                         {
       
   341                         // value is changed, make whole field selected
       
   342                         iIsBeingEditedWithCursor = EFalse;
       
   343                         }
       
   344                     }
       
   345                 else
       
   346                     {
       
   347                     aHighlightIncrement = 1;
       
   348                     }
       
   349                 }
       
   350             break;
       
   351             }
       
   352     }
       
   353 
       
   354 // ---------------------------------------------------------
       
   355 // CLmkMfneFloat::EnsureValueInLimits
       
   356 // ---------------------------------------------------------
       
   357 //
       
   358 TBool CLmkMfneFloat::EnsureValueInLimits(TReal aValue)
       
   359     {
       
   360     if ( !Math::IsNaN(aValue))
       
   361         {
       
   362         TPtr ptr(iText->Des());
       
   363         if (aValue < iMinimumValue)
       
   364             {
       
   365             TextFromValue(iMinimumValue, ptr);
       
   366             return ETrue;
       
   367             }
       
   368 
       
   369         if (aValue > iMaximumValue)
       
   370             {
       
   371             TextFromValue(iMaximumValue, ptr);
       
   372             return ETrue;
       
   373             }
       
   374         }
       
   375     return EFalse;
       
   376     }
       
   377 
       
   378 // ---------------------------------------------------------
       
   379 // CLmkMfneFloat::Text
       
   380 // ---------------------------------------------------------
       
   381 //
       
   382 const TDesC& CLmkMfneFloat::Text() const
       
   383     {
       
   384     TPtr ptr = (iText->Des());
       
   385     AknTextUtils::DisplayTextLanguageSpecificNumberConversion( ptr );
       
   386     return *iText;
       
   387     }
       
   388 
       
   389 // ---------------------------------------------------------
       
   390 // CLmkMfneFloat::MaxNumOfChars
       
   391 // ---------------------------------------------------------
       
   392 //
       
   393 TInt CLmkMfneFloat::MaxNumOfChars() const
       
   394     {
       
   395     return iMaxDigits + KNumOtherSymbols;
       
   396     }
       
   397 
       
   398 // ---------------------------------------------------------
       
   399 // CLmkMfneFloat::TextHasDecimalSeparator
       
   400 // ---------------------------------------------------------
       
   401 //
       
   402 TBool CLmkMfneFloat::IsDecimalSeparatorAllowed(const TDesC& aText) const
       
   403     {
       
   404     if (Math::IsNaN(ValueFromText(aText)))
       
   405         {
       
   406         return EFalse;
       
   407         }
       
   408 
       
   409     TLocale locale;
       
   410     TChar point = locale.DecimalSeparator();
       
   411     TInt i = 0;
       
   412     while (i < aText.Length())
       
   413         {
       
   414         if (TChar(aText[i++]) == point)
       
   415             {
       
   416             return EFalse;
       
   417             }
       
   418         }
       
   419 
       
   420     return (aText.Length() < MaxNumOfChars());
       
   421     }
       
   422 
       
   423 // ---------------------------------------------------------
       
   424 // CLmkMfneFloat::ValueFromText
       
   425 // ---------------------------------------------------------
       
   426 //
       
   427 TBool CLmkMfneFloat::IsMoreDigitsAllowed(const TDesC& aText) const
       
   428     {
       
   429     // check that number of allowed digits is less then iMaxDigits
       
   430     TInt digits = 0, decimalDigits = 0;
       
   431     TInt isDecimalPart = EFalse;
       
   432     TLocale locale;
       
   433     TChar point = locale.DecimalSeparator();
       
   434 
       
   435     // if string starts with 0, then only decimal point is allowed
       
   436     _LIT(KSingleZero, "0");
       
   437     _LIT(KMinusZero, "-0");
       
   438 
       
   439     if (aText == KSingleZero || aText == KMinusZero)
       
   440         {
       
   441         return EFalse;
       
   442         }
       
   443 
       
   444     // other cases - check total amount of digits
       
   445     // and amount of decimal digits
       
   446     for (TInt i = 0; i < aText.Length(); i++)
       
   447         {
       
   448         if (IsAnyDigit(aText[i]))
       
   449             {
       
   450             digits++;
       
   451             }
       
   452         if (isDecimalPart)
       
   453             {
       
   454             decimalDigits++;
       
   455             }
       
   456         if (aText[i] == point)
       
   457             {
       
   458             isDecimalPart = ETrue;
       
   459             }
       
   460         }
       
   461     return ((digits < iMaxDigits) && (decimalDigits < iMaxDecimalDigits));
       
   462     }
       
   463 
       
   464 // ---------------------------------------------------------
       
   465 // CLmkMfneFloat::ValueFromText
       
   466 // ---------------------------------------------------------
       
   467 //
       
   468 TReal CLmkMfneFloat::ValueFromText(const TDesC& aText) const
       
   469     {
       
   470     if (aText.Length() == 0)
       
   471         {
       
   472         return Nan();
       
   473         }
       
   474 
       
   475     TBool isNegative(EFalse);
       
   476     TInt integer(0);
       
   477     TInt integerDigits(0);
       
   478     TBool fractionPart(EFalse);
       
   479     TInt fraction(0);
       
   480     TInt fractionDigits(0);
       
   481     TLocale locale;
       
   482 
       
   483     for (TInt i = 0; i < aText.Length(); i++)
       
   484         {
       
   485         TChar ch(aText[i]);
       
   486         if (ch == '-')
       
   487             {
       
   488             __ASSERT_DEBUG(i == 0, Panic(KErrGeneral));
       
   489             isNegative = ETrue;
       
   490             continue;
       
   491             }
       
   492 
       
   493         if (ch == locale.DecimalSeparator())
       
   494             {
       
   495             __ASSERT_DEBUG(fractionPart == EFalse, Panic(KErrGeneral));
       
   496             fractionPart = ETrue;
       
   497             continue;
       
   498             }
       
   499 
       
   500         TInt val = ch.GetNumericValue();
       
   501         if (val >= 0)
       
   502             {
       
   503             if (!fractionPart)
       
   504                 {
       
   505                 integer = integer * 10 + val;
       
   506                 integerDigits++;
       
   507                 }
       
   508             else
       
   509                 {
       
   510                 fraction = fraction * 10 + val;
       
   511                 fractionDigits++;
       
   512                 }
       
   513             }
       
   514         }
       
   515 
       
   516     // integer part must contain at least "0".
       
   517     if (integerDigits < 1)
       
   518         {
       
   519         return Nan();
       
   520         }
       
   521 
       
   522     TReal value(fraction);
       
   523     for (TInt i = 0; i < fractionDigits; i++)
       
   524         {
       
   525         value /= 10;
       
   526         }
       
   527 
       
   528     value += TReal(integer);
       
   529     return (isNegative) ? -value : value;
       
   530     }
       
   531 
       
   532 // ---------------------------------------------------------
       
   533 // CLmkMfneFloat::TextFromValue
       
   534 // ---------------------------------------------------------
       
   535 //
       
   536 void CLmkMfneFloat::TextFromValue(TReal aValue, TDes& aText) const
       
   537     {
       
   538     aText.SetLength(0);
       
   539 
       
   540     if (Math::IsNaN(aValue))
       
   541         {
       
   542         return;
       
   543         }
       
   544 
       
   545     TRealFormat format;
       
   546     format.iType = KRealFormatFixed;
       
   547     format.iTriLen = 0; // no triad separations
       
   548     format.iWidth = MaxNumOfChars();
       
   549     format.iPlaces = (aValue == 0) ? 0 : iMaxDecimalDigits;
       
   550 
       
   551     // convert real value to a string
       
   552     aText.Num(aValue, format);
       
   553 
       
   554     // cut trailing zeroes from decimal part
       
   555     TLocale locale;
       
   556     TInt pointIndex = aText.Locate(locale.DecimalSeparator());
       
   557     if (pointIndex != KErrNotFound)
       
   558         {
       
   559         TInt newLength = aText.Length();
       
   560         for (TInt i = aText.Length() - 1; i > pointIndex; i--)
       
   561             {
       
   562             if (aText[i] == '0')
       
   563                 {
       
   564                 newLength--;
       
   565                 }
       
   566             else
       
   567                 {
       
   568                 break;
       
   569                 }
       
   570             }
       
   571 
       
   572         // if only decimal point left, cut it also
       
   573         if (aText[newLength-1] == locale.DecimalSeparator())
       
   574             {
       
   575             newLength--;
       
   576             }
       
   577 
       
   578         aText.SetLength(newLength);
       
   579         }
       
   580     }